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-2018, 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 HAVE_TERMIOS_H
37 #include <termios.h>
38 #endif
39 
40 #include "getopt_long.h"
41 
42 #include "access/attnum.h"
43 #include "access/sysattr.h"
44 #include "access/transam.h"
45 #include "catalog/pg_aggregate_d.h"
46 #include "catalog/pg_am_d.h"
47 #include "catalog/pg_attribute_d.h"
48 #include "catalog/pg_cast_d.h"
49 #include "catalog/pg_class_d.h"
50 #include "catalog/pg_default_acl_d.h"
51 #include "catalog/pg_largeobject_d.h"
52 #include "catalog/pg_largeobject_metadata_d.h"
53 #include "catalog/pg_proc_d.h"
54 #include "catalog/pg_trigger_d.h"
55 #include "catalog/pg_type_d.h"
56 #include "libpq/libpq-fs.h"
57 
58 #include "dumputils.h"
59 #include "parallel.h"
60 #include "pg_backup_db.h"
61 #include "pg_backup_utils.h"
62 #include "pg_dump.h"
63 #include "fe_utils/connect.h"
64 #include "fe_utils/string_utils.h"
65 
66 
67 typedef struct
68 {
69 	const char *descr;			/* comment for an object */
70 	Oid			classoid;		/* object class (catalog OID) */
71 	Oid			objoid;			/* object OID */
72 	int			objsubid;		/* subobject (table column #) */
73 } CommentItem;
74 
75 typedef struct
76 {
77 	const char *provider;		/* label provider of this security label */
78 	const char *label;			/* security label for an object */
79 	Oid			classoid;		/* object class (catalog OID) */
80 	Oid			objoid;			/* object OID */
81 	int			objsubid;		/* subobject (table column #) */
82 } SecLabelItem;
83 
84 typedef enum OidOptions
85 {
86 	zeroAsOpaque = 1,
87 	zeroAsAny = 2,
88 	zeroAsStar = 4,
89 	zeroAsNone = 8
90 } OidOptions;
91 
92 /* global decls */
93 bool		g_verbose;			/* User wants verbose narration of our
94 								 * activities. */
95 static bool dosync = true;		/* Issue fsync() to make dump durable on disk. */
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  */
139 #define fmtQualifiedDumpable(obj) \
140 	fmtQualifiedId((obj)->dobj.namespace->dobj.name, \
141 				   (obj)->dobj.name)
142 
143 static void help(const char *progname);
144 static void setup_connection(Archive *AH,
145 				 const char *dumpencoding, const char *dumpsnapshot,
146 				 char *use_role);
147 static ArchiveFormat parseArchiveFormat(const char *format, ArchiveMode *mode);
148 static void expand_schema_name_patterns(Archive *fout,
149 							SimpleStringList *patterns,
150 							SimpleOidList *oids,
151 							bool strict_names);
152 static void expand_table_name_patterns(Archive *fout,
153 						   SimpleStringList *patterns,
154 						   SimpleOidList *oids,
155 						   bool strict_names);
156 static NamespaceInfo *findNamespace(Archive *fout, Oid nsoid);
157 static void dumpTableData(Archive *fout, TableDataInfo *tdinfo);
158 static void refreshMatViewData(Archive *fout, TableDataInfo *tdinfo);
159 static void guessConstraintInheritance(TableInfo *tblinfo, int numTables);
160 static void dumpComment(Archive *fout, const char *type, const char *name,
161 			const char *namespace, const char *owner,
162 			CatalogId catalogId, int subid, DumpId dumpId);
163 static int findComments(Archive *fout, Oid classoid, Oid objoid,
164 			 CommentItem **items);
165 static int	collectComments(Archive *fout, CommentItem **items);
166 static void dumpSecLabel(Archive *fout, const char *type, const char *name,
167 			 const char *namespace, const char *owner,
168 			 CatalogId catalogId, int subid, DumpId dumpId);
169 static int findSecLabels(Archive *fout, Oid classoid, Oid objoid,
170 			  SecLabelItem **items);
171 static int	collectSecLabels(Archive *fout, SecLabelItem **items);
172 static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
173 static void dumpNamespace(Archive *fout, NamespaceInfo *nspinfo);
174 static void dumpExtension(Archive *fout, ExtensionInfo *extinfo);
175 static void dumpType(Archive *fout, TypeInfo *tyinfo);
176 static void dumpBaseType(Archive *fout, TypeInfo *tyinfo);
177 static void dumpEnumType(Archive *fout, TypeInfo *tyinfo);
178 static void dumpRangeType(Archive *fout, TypeInfo *tyinfo);
179 static void dumpUndefinedType(Archive *fout, TypeInfo *tyinfo);
180 static void dumpDomain(Archive *fout, TypeInfo *tyinfo);
181 static void dumpCompositeType(Archive *fout, TypeInfo *tyinfo);
182 static void dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo);
183 static void dumpShellType(Archive *fout, ShellTypeInfo *stinfo);
184 static void dumpProcLang(Archive *fout, ProcLangInfo *plang);
185 static void dumpFunc(Archive *fout, FuncInfo *finfo);
186 static void dumpCast(Archive *fout, CastInfo *cast);
187 static void dumpTransform(Archive *fout, TransformInfo *transform);
188 static void dumpOpr(Archive *fout, OprInfo *oprinfo);
189 static void dumpAccessMethod(Archive *fout, AccessMethodInfo *oprinfo);
190 static void dumpOpclass(Archive *fout, OpclassInfo *opcinfo);
191 static void dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo);
192 static void dumpCollation(Archive *fout, CollInfo *collinfo);
193 static void dumpConversion(Archive *fout, ConvInfo *convinfo);
194 static void dumpRule(Archive *fout, RuleInfo *rinfo);
195 static void dumpAgg(Archive *fout, AggInfo *agginfo);
196 static void dumpTrigger(Archive *fout, TriggerInfo *tginfo);
197 static void dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo);
198 static void dumpTable(Archive *fout, TableInfo *tbinfo);
199 static void dumpTableSchema(Archive *fout, TableInfo *tbinfo);
200 static void dumpAttrDef(Archive *fout, AttrDefInfo *adinfo);
201 static void dumpSequence(Archive *fout, TableInfo *tbinfo);
202 static void dumpSequenceData(Archive *fout, TableDataInfo *tdinfo);
203 static void dumpIndex(Archive *fout, IndxInfo *indxinfo);
204 static void dumpIndexAttach(Archive *fout, IndexAttachInfo *attachinfo);
205 static void dumpStatisticsExt(Archive *fout, StatsExtInfo *statsextinfo);
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, char relkind);
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);
253 static const char *getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts);
254 static void getBlobs(Archive *fout);
255 static void dumpBlob(Archive *fout, BlobInfo *binfo);
256 static int	dumpBlobs(Archive *fout, void *arg);
257 static void dumpPolicy(Archive *fout, PolicyInfo *polinfo);
258 static void dumpPublication(Archive *fout, PublicationInfo *pubinfo);
259 static void dumpPublicationTable(Archive *fout, PublicationRelInfo *pubrinfo);
260 static void dumpSubscription(Archive *fout, SubscriptionInfo *subinfo);
261 static void dumpDatabase(Archive *AH);
262 static void dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
263 				   const char *dbname, Oid dboid);
264 static void dumpEncoding(Archive *AH);
265 static void dumpStdStrings(Archive *AH);
266 static void dumpSearchPath(Archive *AH);
267 static void binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
268 										 PQExpBuffer upgrade_buffer,
269 										 Oid pg_type_oid,
270 										 bool force_array_type);
271 static bool binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
272 										PQExpBuffer upgrade_buffer, Oid pg_rel_oid);
273 static void binary_upgrade_set_pg_class_oids(Archive *fout,
274 								 PQExpBuffer upgrade_buffer,
275 								 Oid pg_class_oid, bool is_index);
276 static void binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
277 								DumpableObject *dobj,
278 								const char *objtype,
279 								const char *objname,
280 								const char *objnamespace);
281 static const char *getAttrName(int attrnum, TableInfo *tblInfo);
282 static const char *fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer);
283 static bool nonemptyReloptions(const char *reloptions);
284 static void appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
285 						const char *prefix, Archive *fout);
286 static char *get_synchronized_snapshot(Archive *fout);
287 static void setupDumpWorker(Archive *AHX);
288 static TableInfo *getRootTableInfo(TableInfo *tbinfo);
289 
290 
291 int
main(int argc,char ** argv)292 main(int argc, char **argv)
293 {
294 	int			c;
295 	const char *filename = NULL;
296 	const char *format = "p";
297 	TableInfo  *tblinfo;
298 	int			numTables;
299 	DumpableObject **dobjs;
300 	int			numObjs;
301 	DumpableObject *boundaryObjs;
302 	int			i;
303 	int			optindex;
304 	RestoreOptions *ropt;
305 	Archive    *fout;			/* the script file */
306 	const char *dumpencoding = NULL;
307 	const char *dumpsnapshot = NULL;
308 	char	   *use_role = NULL;
309 	int			numWorkers = 1;
310 	int			compressLevel = -1;
311 	int			plainText = 0;
312 	ArchiveFormat archiveFormat = archUnknown;
313 	ArchiveMode archiveMode;
314 
315 	static DumpOptions dopt;
316 
317 	static struct option long_options[] = {
318 		{"data-only", no_argument, NULL, 'a'},
319 		{"blobs", no_argument, NULL, 'b'},
320 		{"no-blobs", no_argument, NULL, 'B'},
321 		{"clean", no_argument, NULL, 'c'},
322 		{"create", no_argument, NULL, 'C'},
323 		{"dbname", required_argument, NULL, 'd'},
324 		{"file", required_argument, NULL, 'f'},
325 		{"format", required_argument, NULL, 'F'},
326 		{"host", required_argument, NULL, 'h'},
327 		{"jobs", 1, NULL, 'j'},
328 		{"no-reconnect", no_argument, NULL, 'R'},
329 		{"oids", no_argument, NULL, 'o'},
330 		{"no-owner", no_argument, NULL, 'O'},
331 		{"port", required_argument, NULL, 'p'},
332 		{"schema", required_argument, NULL, 'n'},
333 		{"exclude-schema", required_argument, NULL, 'N'},
334 		{"schema-only", no_argument, NULL, 's'},
335 		{"superuser", required_argument, NULL, 'S'},
336 		{"table", required_argument, NULL, 't'},
337 		{"exclude-table", required_argument, NULL, 'T'},
338 		{"no-password", no_argument, NULL, 'w'},
339 		{"password", no_argument, NULL, 'W'},
340 		{"username", required_argument, NULL, 'U'},
341 		{"verbose", no_argument, NULL, 'v'},
342 		{"no-privileges", no_argument, NULL, 'x'},
343 		{"no-acl", no_argument, NULL, 'x'},
344 		{"compress", required_argument, NULL, 'Z'},
345 		{"encoding", required_argument, NULL, 'E'},
346 		{"help", no_argument, NULL, '?'},
347 		{"version", no_argument, NULL, 'V'},
348 
349 		/*
350 		 * the following options don't have an equivalent short option letter
351 		 */
352 		{"attribute-inserts", no_argument, &dopt.column_inserts, 1},
353 		{"binary-upgrade", no_argument, &dopt.binary_upgrade, 1},
354 		{"column-inserts", no_argument, &dopt.column_inserts, 1},
355 		{"disable-dollar-quoting", no_argument, &dopt.disable_dollar_quoting, 1},
356 		{"disable-triggers", no_argument, &dopt.disable_triggers, 1},
357 		{"enable-row-security", no_argument, &dopt.enable_row_security, 1},
358 		{"exclude-table-data", required_argument, NULL, 4},
359 		{"if-exists", no_argument, &dopt.if_exists, 1},
360 		{"inserts", no_argument, &dopt.dump_inserts, 1},
361 		{"lock-wait-timeout", required_argument, NULL, 2},
362 		{"no-tablespaces", no_argument, &dopt.outputNoTablespaces, 1},
363 		{"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
364 		{"load-via-partition-root", no_argument, &dopt.load_via_partition_root, 1},
365 		{"role", required_argument, NULL, 3},
366 		{"section", required_argument, NULL, 5},
367 		{"serializable-deferrable", no_argument, &dopt.serializable_deferrable, 1},
368 		{"snapshot", required_argument, NULL, 6},
369 		{"strict-names", no_argument, &strict_names, 1},
370 		{"use-set-session-authorization", no_argument, &dopt.use_setsessauth, 1},
371 		{"no-comments", no_argument, &dopt.no_comments, 1},
372 		{"no-publications", no_argument, &dopt.no_publications, 1},
373 		{"no-security-labels", no_argument, &dopt.no_security_labels, 1},
374 		{"no-synchronized-snapshots", no_argument, &dopt.no_synchronized_snapshots, 1},
375 		{"no-unlogged-table-data", no_argument, &dopt.no_unlogged_table_data, 1},
376 		{"no-subscriptions", no_argument, &dopt.no_subscriptions, 1},
377 		{"no-sync", no_argument, NULL, 7},
378 
379 		{NULL, 0, NULL, 0}
380 	};
381 
382 	set_pglocale_pgservice(argv[0], PG_TEXTDOMAIN("pg_dump"));
383 
384 	/*
385 	 * Initialize what we need for parallel execution, especially for thread
386 	 * support on Windows.
387 	 */
388 	init_parallel_dump_utils();
389 
390 	g_verbose = false;
391 
392 	strcpy(g_comment_start, "-- ");
393 	g_comment_end[0] = '\0';
394 	strcpy(g_opaque_type, "opaque");
395 
396 	progname = get_progname(argv[0]);
397 
398 	if (argc > 1)
399 	{
400 		if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
401 		{
402 			help(progname);
403 			exit_nicely(0);
404 		}
405 		if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
406 		{
407 			puts("pg_dump (PostgreSQL) " PG_VERSION);
408 			exit_nicely(0);
409 		}
410 	}
411 
412 	InitDumpOptions(&dopt);
413 
414 	while ((c = getopt_long(argc, argv, "abBcCd:E:f:F:h:j:n:N:oOp:RsS:t:T:U:vwWxZ:",
415 							long_options, &optindex)) != -1)
416 	{
417 		switch (c)
418 		{
419 			case 'a':			/* Dump data only */
420 				dopt.dataOnly = true;
421 				break;
422 
423 			case 'b':			/* Dump blobs */
424 				dopt.outputBlobs = true;
425 				break;
426 
427 			case 'B':			/* Don't dump blobs */
428 				dopt.dontOutputBlobs = true;
429 				break;
430 
431 			case 'c':			/* clean (i.e., drop) schema prior to create */
432 				dopt.outputClean = 1;
433 				break;
434 
435 			case 'C':			/* Create DB */
436 				dopt.outputCreateDB = 1;
437 				break;
438 
439 			case 'd':			/* database name */
440 				dopt.cparams.dbname = pg_strdup(optarg);
441 				break;
442 
443 			case 'E':			/* Dump encoding */
444 				dumpencoding = pg_strdup(optarg);
445 				break;
446 
447 			case 'f':
448 				filename = pg_strdup(optarg);
449 				break;
450 
451 			case 'F':
452 				format = pg_strdup(optarg);
453 				break;
454 
455 			case 'h':			/* server host */
456 				dopt.cparams.pghost = pg_strdup(optarg);
457 				break;
458 
459 			case 'j':			/* number of dump jobs */
460 				numWorkers = atoi(optarg);
461 				break;
462 
463 			case 'n':			/* include schema(s) */
464 				simple_string_list_append(&schema_include_patterns, optarg);
465 				dopt.include_everything = false;
466 				break;
467 
468 			case 'N':			/* exclude schema(s) */
469 				simple_string_list_append(&schema_exclude_patterns, optarg);
470 				break;
471 
472 			case 'o':			/* Dump oids */
473 				dopt.oids = true;
474 				break;
475 
476 			case 'O':			/* Don't reconnect to match owner */
477 				dopt.outputNoOwner = 1;
478 				break;
479 
480 			case 'p':			/* server port */
481 				dopt.cparams.pgport = pg_strdup(optarg);
482 				break;
483 
484 			case 'R':
485 				/* no-op, still accepted for backwards compatibility */
486 				break;
487 
488 			case 's':			/* dump schema only */
489 				dopt.schemaOnly = true;
490 				break;
491 
492 			case 'S':			/* Username for superuser in plain text output */
493 				dopt.outputSuperuser = pg_strdup(optarg);
494 				break;
495 
496 			case 't':			/* include table(s) */
497 				simple_string_list_append(&table_include_patterns, optarg);
498 				dopt.include_everything = false;
499 				break;
500 
501 			case 'T':			/* exclude table(s) */
502 				simple_string_list_append(&table_exclude_patterns, optarg);
503 				break;
504 
505 			case 'U':
506 				dopt.cparams.username = pg_strdup(optarg);
507 				break;
508 
509 			case 'v':			/* verbose */
510 				g_verbose = true;
511 				break;
512 
513 			case 'w':
514 				dopt.cparams.promptPassword = TRI_NO;
515 				break;
516 
517 			case 'W':
518 				dopt.cparams.promptPassword = TRI_YES;
519 				break;
520 
521 			case 'x':			/* skip ACL dump */
522 				dopt.aclsSkip = true;
523 				break;
524 
525 			case 'Z':			/* Compression Level */
526 				compressLevel = atoi(optarg);
527 				if (compressLevel < 0 || compressLevel > 9)
528 				{
529 					write_msg(NULL, "compression level must be in range 0..9\n");
530 					exit_nicely(1);
531 				}
532 				break;
533 
534 			case 0:
535 				/* This covers the long options. */
536 				break;
537 
538 			case 2:				/* lock-wait-timeout */
539 				dopt.lockWaitTimeout = pg_strdup(optarg);
540 				break;
541 
542 			case 3:				/* SET ROLE */
543 				use_role = pg_strdup(optarg);
544 				break;
545 
546 			case 4:				/* exclude table(s) data */
547 				simple_string_list_append(&tabledata_exclude_patterns, optarg);
548 				break;
549 
550 			case 5:				/* section */
551 				set_dump_section(optarg, &dopt.dumpSections);
552 				break;
553 
554 			case 6:				/* snapshot */
555 				dumpsnapshot = pg_strdup(optarg);
556 				break;
557 
558 			case 7:				/* no-sync */
559 				dosync = false;
560 				break;
561 
562 			default:
563 				fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
564 				exit_nicely(1);
565 		}
566 	}
567 
568 	/*
569 	 * Non-option argument specifies database name as long as it wasn't
570 	 * already specified with -d / --dbname
571 	 */
572 	if (optind < argc && dopt.cparams.dbname == NULL)
573 		dopt.cparams.dbname = argv[optind++];
574 
575 	/* Complain if any arguments remain */
576 	if (optind < argc)
577 	{
578 		fprintf(stderr, _("%s: too many command-line arguments (first is \"%s\")\n"),
579 				progname, argv[optind]);
580 		fprintf(stderr, _("Try \"%s --help\" for more information.\n"),
581 				progname);
582 		exit_nicely(1);
583 	}
584 
585 	/* --column-inserts implies --inserts */
586 	if (dopt.column_inserts)
587 		dopt.dump_inserts = 1;
588 
589 	/*
590 	 * Binary upgrade mode implies dumping sequence data even in schema-only
591 	 * mode.  This is not exposed as a separate option, but kept separate
592 	 * internally for clarity.
593 	 */
594 	if (dopt.binary_upgrade)
595 		dopt.sequence_data = 1;
596 
597 	if (dopt.dataOnly && dopt.schemaOnly)
598 	{
599 		write_msg(NULL, "options -s/--schema-only and -a/--data-only cannot be used together\n");
600 		exit_nicely(1);
601 	}
602 
603 	if (dopt.dataOnly && dopt.outputClean)
604 	{
605 		write_msg(NULL, "options -c/--clean and -a/--data-only cannot be used together\n");
606 		exit_nicely(1);
607 	}
608 
609 	if (dopt.dump_inserts && dopt.oids)
610 	{
611 		write_msg(NULL, "options --inserts/--column-inserts and -o/--oids cannot be used together\n");
612 		write_msg(NULL, "(The INSERT command cannot set OIDs.)\n");
613 		exit_nicely(1);
614 	}
615 
616 	if (dopt.if_exists && !dopt.outputClean)
617 		exit_horribly(NULL, "option --if-exists requires option -c/--clean\n");
618 
619 	/* Identify archive format to emit */
620 	archiveFormat = parseArchiveFormat(format, &archiveMode);
621 
622 	/* archiveFormat specific setup */
623 	if (archiveFormat == archNull)
624 		plainText = 1;
625 
626 	/* Custom and directory formats are compressed by default, others not */
627 	if (compressLevel == -1)
628 	{
629 #ifdef HAVE_LIBZ
630 		if (archiveFormat == archCustom || archiveFormat == archDirectory)
631 			compressLevel = Z_DEFAULT_COMPRESSION;
632 		else
633 #endif
634 			compressLevel = 0;
635 	}
636 
637 #ifndef HAVE_LIBZ
638 	if (compressLevel != 0)
639 		write_msg(NULL, "WARNING: requested compression not available in this "
640 				  "installation -- archive will be uncompressed\n");
641 	compressLevel = 0;
642 #endif
643 
644 	/*
645 	 * If emitting an archive format, we always want to emit a DATABASE item,
646 	 * in case --create is specified at pg_restore time.
647 	 */
648 	if (!plainText)
649 		dopt.outputCreateDB = 1;
650 
651 	/*
652 	 * On Windows we can only have at most MAXIMUM_WAIT_OBJECTS (= 64 usually)
653 	 * parallel jobs because that's the maximum limit for the
654 	 * WaitForMultipleObjects() call.
655 	 */
656 	if (numWorkers <= 0
657 #ifdef WIN32
658 		|| numWorkers > MAXIMUM_WAIT_OBJECTS
659 #endif
660 		)
661 		exit_horribly(NULL, "invalid number of parallel jobs\n");
662 
663 	/* Parallel backup only in the directory archive format so far */
664 	if (archiveFormat != archDirectory && numWorkers > 1)
665 		exit_horribly(NULL, "parallel backup only supported by the directory format\n");
666 
667 	/* Open the output file */
668 	fout = CreateArchive(filename, archiveFormat, compressLevel, dosync,
669 						 archiveMode, setupDumpWorker);
670 
671 	/* Make dump options accessible right away */
672 	SetArchiveOptions(fout, &dopt, NULL);
673 
674 	/* Register the cleanup hook */
675 	on_exit_close_archive(fout);
676 
677 	/* Let the archiver know how noisy to be */
678 	fout->verbose = g_verbose;
679 
680 	/*
681 	 * We allow the server to be back to 8.0, and up to any minor release of
682 	 * our own major version.  (See also version check in pg_dumpall.c.)
683 	 */
684 	fout->minRemoteVersion = 80000;
685 	fout->maxRemoteVersion = (PG_VERSION_NUM / 100) * 100 + 99;
686 
687 	fout->numWorkers = numWorkers;
688 
689 	/*
690 	 * Open the database using the Archiver, so it knows about it. Errors mean
691 	 * death.
692 	 */
693 	ConnectDatabase(fout, &dopt.cparams, false);
694 	setup_connection(fout, dumpencoding, dumpsnapshot, use_role);
695 
696 	/*
697 	 * Disable security label support if server version < v9.1.x (prevents
698 	 * access to nonexistent pg_seclabel catalog)
699 	 */
700 	if (fout->remoteVersion < 90100)
701 		dopt.no_security_labels = 1;
702 
703 	/*
704 	 * On hot standbys, never try to dump unlogged table data, since it will
705 	 * just throw an error.
706 	 */
707 	if (fout->isStandby)
708 		dopt.no_unlogged_table_data = true;
709 
710 	/* Select the appropriate subquery to convert user IDs to names */
711 	if (fout->remoteVersion >= 80100)
712 		username_subquery = "SELECT rolname FROM pg_catalog.pg_roles WHERE oid =";
713 	else
714 		username_subquery = "SELECT usename FROM pg_catalog.pg_user WHERE usesysid =";
715 
716 	/* check the version for the synchronized snapshots feature */
717 	if (numWorkers > 1 && fout->remoteVersion < 90200
718 		&& !dopt.no_synchronized_snapshots)
719 		exit_horribly(NULL,
720 					  "Synchronized snapshots are not supported by this server version.\n"
721 					  "Run with --no-synchronized-snapshots instead if you do not need\n"
722 					  "synchronized snapshots.\n");
723 
724 	/* check the version when a snapshot is explicitly specified by user */
725 	if (dumpsnapshot && fout->remoteVersion < 90200)
726 		exit_horribly(NULL,
727 					  "Exported snapshots are not supported by this server version.\n");
728 
729 	/*
730 	 * Find the last built-in OID, if needed (prior to 8.1)
731 	 *
732 	 * With 8.1 and above, we can just use FirstNormalObjectId - 1.
733 	 */
734 	if (fout->remoteVersion < 80100)
735 		g_last_builtin_oid = findLastBuiltinOid_V71(fout);
736 	else
737 		g_last_builtin_oid = FirstNormalObjectId - 1;
738 
739 	if (g_verbose)
740 		write_msg(NULL, "last built-in OID is %u\n", g_last_builtin_oid);
741 
742 	/* Expand schema selection patterns into OID lists */
743 	if (schema_include_patterns.head != NULL)
744 	{
745 		expand_schema_name_patterns(fout, &schema_include_patterns,
746 									&schema_include_oids,
747 									strict_names);
748 		if (schema_include_oids.head == NULL)
749 			exit_horribly(NULL, "no matching schemas were found\n");
750 	}
751 	expand_schema_name_patterns(fout, &schema_exclude_patterns,
752 								&schema_exclude_oids,
753 								false);
754 	/* non-matching exclusion patterns aren't an error */
755 
756 	/* Expand table selection patterns into OID lists */
757 	if (table_include_patterns.head != NULL)
758 	{
759 		expand_table_name_patterns(fout, &table_include_patterns,
760 								   &table_include_oids,
761 								   strict_names);
762 		if (table_include_oids.head == NULL)
763 			exit_horribly(NULL, "no matching tables were found\n");
764 	}
765 	expand_table_name_patterns(fout, &table_exclude_patterns,
766 							   &table_exclude_oids,
767 							   false);
768 
769 	expand_table_name_patterns(fout, &tabledata_exclude_patterns,
770 							   &tabledata_exclude_oids,
771 							   false);
772 
773 	/* non-matching exclusion patterns aren't an error */
774 
775 	/*
776 	 * Dumping blobs is the default for dumps where an inclusion switch is not
777 	 * used (an "include everything" dump).  -B can be used to exclude blobs
778 	 * from those dumps.  -b can be used to include blobs even when an
779 	 * inclusion switch is used.
780 	 *
781 	 * -s means "schema only" and blobs are data, not schema, so we never
782 	 * include blobs when -s is used.
783 	 */
784 	if (dopt.include_everything && !dopt.schemaOnly && !dopt.dontOutputBlobs)
785 		dopt.outputBlobs = true;
786 
787 	/*
788 	 * Now scan the database and create DumpableObject structs for all the
789 	 * objects we intend to dump.
790 	 */
791 	tblinfo = getSchemaData(fout, &numTables);
792 
793 	if (fout->remoteVersion < 80400)
794 		guessConstraintInheritance(tblinfo, numTables);
795 
796 	if (!dopt.schemaOnly)
797 	{
798 		getTableData(&dopt, tblinfo, numTables, dopt.oids, 0);
799 		buildMatViewRefreshDependencies(fout);
800 		if (dopt.dataOnly)
801 			getTableDataFKConstraints();
802 	}
803 
804 	if (dopt.schemaOnly && dopt.sequence_data)
805 		getTableData(&dopt, tblinfo, numTables, dopt.oids, RELKIND_SEQUENCE);
806 
807 	/*
808 	 * In binary-upgrade mode, we do not have to worry about the actual blob
809 	 * data or the associated metadata that resides in the pg_largeobject and
810 	 * pg_largeobject_metadata tables, respectively.
811 	 *
812 	 * However, we do need to collect blob information as there may be
813 	 * comments or other information on blobs that we do need to dump out.
814 	 */
815 	if (dopt.outputBlobs || dopt.binary_upgrade)
816 		getBlobs(fout);
817 
818 	/*
819 	 * Collect dependency data to assist in ordering the objects.
820 	 */
821 	getDependencies(fout);
822 
823 	/* Lastly, create dummy objects to represent the section boundaries */
824 	boundaryObjs = createBoundaryObjects();
825 
826 	/* Get pointers to all the known DumpableObjects */
827 	getDumpableObjects(&dobjs, &numObjs);
828 
829 	/*
830 	 * Add dummy dependencies to enforce the dump section ordering.
831 	 */
832 	addBoundaryDependencies(dobjs, numObjs, boundaryObjs);
833 
834 	/*
835 	 * Sort the objects into a safe dump order (no forward references).
836 	 *
837 	 * We rely on dependency information to help us determine a safe order, so
838 	 * the initial sort is mostly for cosmetic purposes: we sort by name to
839 	 * ensure that logically identical schemas will dump identically.
840 	 */
841 	sortDumpableObjectsByTypeName(dobjs, numObjs);
842 
843 	/* If we do a parallel dump, we want the largest tables to go first */
844 	if (archiveFormat == archDirectory && numWorkers > 1)
845 		sortDataAndIndexObjectsBySize(dobjs, numObjs);
846 
847 	sortDumpableObjects(dobjs, numObjs,
848 						boundaryObjs[0].dumpId, boundaryObjs[1].dumpId);
849 
850 	/*
851 	 * Create archive TOC entries for all the objects to be dumped, in a safe
852 	 * order.
853 	 */
854 
855 	/* First the special ENCODING, STDSTRINGS, and SEARCHPATH entries. */
856 	dumpEncoding(fout);
857 	dumpStdStrings(fout);
858 	dumpSearchPath(fout);
859 
860 	/* The database items are always next, unless we don't want them at all */
861 	if (dopt.outputCreateDB)
862 		dumpDatabase(fout);
863 
864 	/* Now the rearrangeable objects. */
865 	for (i = 0; i < numObjs; i++)
866 		dumpDumpableObject(fout, dobjs[i]);
867 
868 	/*
869 	 * Set up options info to ensure we dump what we want.
870 	 */
871 	ropt = NewRestoreOptions();
872 	ropt->filename = filename;
873 
874 	/* if you change this list, see dumpOptionsFromRestoreOptions */
875 	ropt->cparams.dbname = dopt.cparams.dbname ? pg_strdup(dopt.cparams.dbname) : NULL;
876 	ropt->cparams.pgport = dopt.cparams.pgport ? pg_strdup(dopt.cparams.pgport) : NULL;
877 	ropt->cparams.pghost = dopt.cparams.pghost ? pg_strdup(dopt.cparams.pghost) : NULL;
878 	ropt->cparams.username = dopt.cparams.username ? pg_strdup(dopt.cparams.username) : NULL;
879 	ropt->cparams.promptPassword = dopt.cparams.promptPassword;
880 	ropt->dropSchema = dopt.outputClean;
881 	ropt->dataOnly = dopt.dataOnly;
882 	ropt->schemaOnly = dopt.schemaOnly;
883 	ropt->if_exists = dopt.if_exists;
884 	ropt->column_inserts = dopt.column_inserts;
885 	ropt->dumpSections = dopt.dumpSections;
886 	ropt->aclsSkip = dopt.aclsSkip;
887 	ropt->superuser = dopt.outputSuperuser;
888 	ropt->createDB = dopt.outputCreateDB;
889 	ropt->noOwner = dopt.outputNoOwner;
890 	ropt->noTablespace = dopt.outputNoTablespaces;
891 	ropt->disable_triggers = dopt.disable_triggers;
892 	ropt->use_setsessauth = dopt.use_setsessauth;
893 	ropt->disable_dollar_quoting = dopt.disable_dollar_quoting;
894 	ropt->dump_inserts = dopt.dump_inserts;
895 	ropt->no_comments = dopt.no_comments;
896 	ropt->no_publications = dopt.no_publications;
897 	ropt->no_security_labels = dopt.no_security_labels;
898 	ropt->no_subscriptions = dopt.no_subscriptions;
899 	ropt->lockWaitTimeout = dopt.lockWaitTimeout;
900 	ropt->include_everything = dopt.include_everything;
901 	ropt->enable_row_security = dopt.enable_row_security;
902 	ropt->sequence_data = dopt.sequence_data;
903 	ropt->binary_upgrade = dopt.binary_upgrade;
904 
905 	if (compressLevel == -1)
906 		ropt->compression = 0;
907 	else
908 		ropt->compression = compressLevel;
909 
910 	ropt->suppressDumpWarnings = true;	/* We've already shown them */
911 
912 	SetArchiveOptions(fout, &dopt, ropt);
913 
914 	/* Mark which entries should be output */
915 	ProcessArchiveRestoreOptions(fout);
916 
917 	/*
918 	 * The archive's TOC entries are now marked as to which ones will actually
919 	 * be output, so we can set up their dependency lists properly. This isn't
920 	 * necessary for plain-text output, though.
921 	 */
922 	if (!plainText)
923 		BuildArchiveDependencies(fout);
924 
925 	/*
926 	 * And finally we can do the actual output.
927 	 *
928 	 * Note: for non-plain-text output formats, the output file is written
929 	 * inside CloseArchive().  This is, um, bizarre; but not worth changing
930 	 * right now.
931 	 */
932 	if (plainText)
933 		RestoreArchive(fout);
934 
935 	CloseArchive(fout);
936 
937 	exit_nicely(0);
938 }
939 
940 
941 static void
help(const char * progname)942 help(const char *progname)
943 {
944 	printf(_("%s dumps a database as a text file or to other formats.\n\n"), progname);
945 	printf(_("Usage:\n"));
946 	printf(_("  %s [OPTION]... [DBNAME]\n"), progname);
947 
948 	printf(_("\nGeneral options:\n"));
949 	printf(_("  -f, --file=FILENAME          output file or directory name\n"));
950 	printf(_("  -F, --format=c|d|t|p         output file format (custom, directory, tar,\n"
951 			 "                               plain text (default))\n"));
952 	printf(_("  -j, --jobs=NUM               use this many parallel jobs to dump\n"));
953 	printf(_("  -v, --verbose                verbose mode\n"));
954 	printf(_("  -V, --version                output version information, then exit\n"));
955 	printf(_("  -Z, --compress=0-9           compression level for compressed formats\n"));
956 	printf(_("  --lock-wait-timeout=TIMEOUT  fail after waiting TIMEOUT for a table lock\n"));
957 	printf(_("  --no-sync                    do not wait for changes to be written safely to disk\n"));
958 	printf(_("  -?, --help                   show this help, then exit\n"));
959 
960 	printf(_("\nOptions controlling the output content:\n"));
961 	printf(_("  -a, --data-only              dump only the data, not the schema\n"));
962 	printf(_("  -b, --blobs                  include large objects in dump\n"));
963 	printf(_("  -B, --no-blobs               exclude large objects in dump\n"));
964 	printf(_("  -c, --clean                  clean (drop) database objects before recreating\n"));
965 	printf(_("  -C, --create                 include commands to create database in dump\n"));
966 	printf(_("  -E, --encoding=ENCODING      dump the data in encoding ENCODING\n"));
967 	printf(_("  -n, --schema=SCHEMA          dump the named schema(s) only\n"));
968 	printf(_("  -N, --exclude-schema=SCHEMA  do NOT dump the named schema(s)\n"));
969 	printf(_("  -o, --oids                   include OIDs in dump\n"));
970 	printf(_("  -O, --no-owner               skip restoration of object ownership in\n"
971 			 "                               plain-text format\n"));
972 	printf(_("  -s, --schema-only            dump only the schema, no data\n"));
973 	printf(_("  -S, --superuser=NAME         superuser user name to use in plain-text format\n"));
974 	printf(_("  -t, --table=TABLE            dump the named table(s) only\n"));
975 	printf(_("  -T, --exclude-table=TABLE    do NOT dump the named table(s)\n"));
976 	printf(_("  -x, --no-privileges          do not dump privileges (grant/revoke)\n"));
977 	printf(_("  --binary-upgrade             for use by upgrade utilities only\n"));
978 	printf(_("  --column-inserts             dump data as INSERT commands with column names\n"));
979 	printf(_("  --disable-dollar-quoting     disable dollar quoting, use SQL standard quoting\n"));
980 	printf(_("  --disable-triggers           disable triggers during data-only restore\n"));
981 	printf(_("  --enable-row-security        enable row security (dump only content user has\n"
982 			 "                               access to)\n"));
983 	printf(_("  --exclude-table-data=TABLE   do NOT dump data for the named table(s)\n"));
984 	printf(_("  --if-exists                  use IF EXISTS when dropping objects\n"));
985 	printf(_("  --inserts                    dump data as INSERT commands, rather than COPY\n"));
986 	printf(_("  --load-via-partition-root    load partitions via the root table\n"));
987 	printf(_("  --no-comments                do not dump comments\n"));
988 	printf(_("  --no-publications            do not dump publications\n"));
989 	printf(_("  --no-security-labels         do not dump security label assignments\n"));
990 	printf(_("  --no-subscriptions           do not dump subscriptions\n"));
991 	printf(_("  --no-synchronized-snapshots  do not use synchronized snapshots in parallel jobs\n"));
992 	printf(_("  --no-tablespaces             do not dump tablespace assignments\n"));
993 	printf(_("  --no-unlogged-table-data     do not dump unlogged table data\n"));
994 	printf(_("  --quote-all-identifiers      quote all identifiers, even if not key words\n"));
995 	printf(_("  --section=SECTION            dump named section (pre-data, data, or post-data)\n"));
996 	printf(_("  --serializable-deferrable    wait until the dump can run without anomalies\n"));
997 	printf(_("  --snapshot=SNAPSHOT          use given snapshot for the dump\n"));
998 	printf(_("  --strict-names               require table and/or schema include patterns to\n"
999 			 "                               match at least one entity each\n"));
1000 	printf(_("  --use-set-session-authorization\n"
1001 			 "                               use SET SESSION AUTHORIZATION commands instead of\n"
1002 			 "                               ALTER OWNER commands to set ownership\n"));
1003 
1004 	printf(_("\nConnection options:\n"));
1005 	printf(_("  -d, --dbname=DBNAME      database to dump\n"));
1006 	printf(_("  -h, --host=HOSTNAME      database server host or socket directory\n"));
1007 	printf(_("  -p, --port=PORT          database server port number\n"));
1008 	printf(_("  -U, --username=NAME      connect as specified database user\n"));
1009 	printf(_("  -w, --no-password        never prompt for password\n"));
1010 	printf(_("  -W, --password           force password prompt (should happen automatically)\n"));
1011 	printf(_("  --role=ROLENAME          do SET ROLE before dump\n"));
1012 
1013 	printf(_("\nIf no database name is supplied, then the PGDATABASE environment\n"
1014 			 "variable value is used.\n\n"));
1015 	printf(_("Report bugs to <pgsql-bugs@postgresql.org>.\n"));
1016 }
1017 
1018 static void
setup_connection(Archive * AH,const char * dumpencoding,const char * dumpsnapshot,char * use_role)1019 setup_connection(Archive *AH, const char *dumpencoding,
1020 				 const char *dumpsnapshot, char *use_role)
1021 {
1022 	DumpOptions *dopt = AH->dopt;
1023 	PGconn	   *conn = GetConnection(AH);
1024 	const char *std_strings;
1025 
1026 	PQclear(ExecuteSqlQueryForSingleRow(AH, ALWAYS_SECURE_SEARCH_PATH_SQL));
1027 
1028 	/*
1029 	 * Set the client encoding if requested.
1030 	 */
1031 	if (dumpencoding)
1032 	{
1033 		if (PQsetClientEncoding(conn, dumpencoding) < 0)
1034 			exit_horribly(NULL, "invalid client encoding \"%s\" specified\n",
1035 						  dumpencoding);
1036 	}
1037 
1038 	/*
1039 	 * Get the active encoding and the standard_conforming_strings setting, so
1040 	 * we know how to escape strings.
1041 	 */
1042 	AH->encoding = PQclientEncoding(conn);
1043 
1044 	std_strings = PQparameterStatus(conn, "standard_conforming_strings");
1045 	AH->std_strings = (std_strings && strcmp(std_strings, "on") == 0);
1046 
1047 	/*
1048 	 * Set the role if requested.  In a parallel dump worker, we'll be passed
1049 	 * use_role == NULL, but AH->use_role is already set (if user specified it
1050 	 * originally) and we should use that.
1051 	 */
1052 	if (!use_role && AH->use_role)
1053 		use_role = AH->use_role;
1054 
1055 	/* Set the role if requested */
1056 	if (use_role && AH->remoteVersion >= 80100)
1057 	{
1058 		PQExpBuffer query = createPQExpBuffer();
1059 
1060 		appendPQExpBuffer(query, "SET ROLE %s", fmtId(use_role));
1061 		ExecuteSqlStatement(AH, query->data);
1062 		destroyPQExpBuffer(query);
1063 
1064 		/* save it for possible later use by parallel workers */
1065 		if (!AH->use_role)
1066 			AH->use_role = pg_strdup(use_role);
1067 	}
1068 
1069 	/* Set the datestyle to ISO to ensure the dump's portability */
1070 	ExecuteSqlStatement(AH, "SET DATESTYLE = ISO");
1071 
1072 	/* Likewise, avoid using sql_standard intervalstyle */
1073 	if (AH->remoteVersion >= 80400)
1074 		ExecuteSqlStatement(AH, "SET INTERVALSTYLE = POSTGRES");
1075 
1076 	/*
1077 	 * Set extra_float_digits so that we can dump float data exactly (given
1078 	 * correctly implemented float I/O code, anyway)
1079 	 */
1080 	if (AH->remoteVersion >= 90000)
1081 		ExecuteSqlStatement(AH, "SET extra_float_digits TO 3");
1082 	else
1083 		ExecuteSqlStatement(AH, "SET extra_float_digits TO 2");
1084 
1085 	/*
1086 	 * If synchronized scanning is supported, disable it, to prevent
1087 	 * unpredictable changes in row ordering across a dump and reload.
1088 	 */
1089 	if (AH->remoteVersion >= 80300)
1090 		ExecuteSqlStatement(AH, "SET synchronize_seqscans TO off");
1091 
1092 	/*
1093 	 * Disable timeouts if supported.
1094 	 */
1095 	ExecuteSqlStatement(AH, "SET statement_timeout = 0");
1096 	if (AH->remoteVersion >= 90300)
1097 		ExecuteSqlStatement(AH, "SET lock_timeout = 0");
1098 	if (AH->remoteVersion >= 90600)
1099 		ExecuteSqlStatement(AH, "SET idle_in_transaction_session_timeout = 0");
1100 
1101 	/*
1102 	 * Quote all identifiers, if requested.
1103 	 */
1104 	if (quote_all_identifiers && AH->remoteVersion >= 90100)
1105 		ExecuteSqlStatement(AH, "SET quote_all_identifiers = true");
1106 
1107 	/*
1108 	 * Adjust row-security mode, if supported.
1109 	 */
1110 	if (AH->remoteVersion >= 90500)
1111 	{
1112 		if (dopt->enable_row_security)
1113 			ExecuteSqlStatement(AH, "SET row_security = on");
1114 		else
1115 			ExecuteSqlStatement(AH, "SET row_security = off");
1116 	}
1117 
1118 	/*
1119 	 * Start transaction-snapshot mode transaction to dump consistent data.
1120 	 */
1121 	ExecuteSqlStatement(AH, "BEGIN");
1122 	if (AH->remoteVersion >= 90100)
1123 	{
1124 		/*
1125 		 * To support the combination of serializable_deferrable with the jobs
1126 		 * option we use REPEATABLE READ for the worker connections that are
1127 		 * passed a snapshot.  As long as the snapshot is acquired in a
1128 		 * SERIALIZABLE, READ ONLY, DEFERRABLE transaction, its use within a
1129 		 * REPEATABLE READ transaction provides the appropriate integrity
1130 		 * guarantees.  This is a kluge, but safe for back-patching.
1131 		 */
1132 		if (dopt->serializable_deferrable && AH->sync_snapshot_id == NULL)
1133 			ExecuteSqlStatement(AH,
1134 								"SET TRANSACTION ISOLATION LEVEL "
1135 								"SERIALIZABLE, READ ONLY, DEFERRABLE");
1136 		else
1137 			ExecuteSqlStatement(AH,
1138 								"SET TRANSACTION ISOLATION LEVEL "
1139 								"REPEATABLE READ, READ ONLY");
1140 	}
1141 	else
1142 	{
1143 		ExecuteSqlStatement(AH,
1144 							"SET TRANSACTION ISOLATION LEVEL "
1145 							"SERIALIZABLE, READ ONLY");
1146 	}
1147 
1148 	/*
1149 	 * If user specified a snapshot to use, select that.  In a parallel dump
1150 	 * worker, we'll be passed dumpsnapshot == NULL, but AH->sync_snapshot_id
1151 	 * is already set (if the server can handle it) and we should use that.
1152 	 */
1153 	if (dumpsnapshot)
1154 		AH->sync_snapshot_id = pg_strdup(dumpsnapshot);
1155 
1156 	if (AH->sync_snapshot_id)
1157 	{
1158 		PQExpBuffer query = createPQExpBuffer();
1159 
1160 		appendPQExpBuffer(query, "SET TRANSACTION SNAPSHOT ");
1161 		appendStringLiteralConn(query, AH->sync_snapshot_id, conn);
1162 		ExecuteSqlStatement(AH, query->data);
1163 		destroyPQExpBuffer(query);
1164 	}
1165 	else if (AH->numWorkers > 1 &&
1166 			 AH->remoteVersion >= 90200 &&
1167 			 !dopt->no_synchronized_snapshots)
1168 	{
1169 		if (AH->isStandby && AH->remoteVersion < 100000)
1170 			exit_horribly(NULL,
1171 						  "Synchronized snapshots on standby servers are not supported by this server version.\n"
1172 						  "Run with --no-synchronized-snapshots instead if you do not need\n"
1173 						  "synchronized snapshots.\n");
1174 
1175 
1176 		AH->sync_snapshot_id = get_synchronized_snapshot(AH);
1177 	}
1178 }
1179 
1180 /* Set up connection for a parallel worker process */
1181 static void
setupDumpWorker(Archive * AH)1182 setupDumpWorker(Archive *AH)
1183 {
1184 	/*
1185 	 * We want to re-select all the same values the master connection is
1186 	 * using.  We'll have inherited directly-usable values in
1187 	 * AH->sync_snapshot_id and AH->use_role, but we need to translate the
1188 	 * inherited encoding value back to a string to pass to setup_connection.
1189 	 */
1190 	setup_connection(AH,
1191 					 pg_encoding_to_char(AH->encoding),
1192 					 NULL,
1193 					 NULL);
1194 }
1195 
1196 static char *
get_synchronized_snapshot(Archive * fout)1197 get_synchronized_snapshot(Archive *fout)
1198 {
1199 	char	   *query = "SELECT pg_catalog.pg_export_snapshot()";
1200 	char	   *result;
1201 	PGresult   *res;
1202 
1203 	res = ExecuteSqlQueryForSingleRow(fout, query);
1204 	result = pg_strdup(PQgetvalue(res, 0, 0));
1205 	PQclear(res);
1206 
1207 	return result;
1208 }
1209 
1210 static ArchiveFormat
parseArchiveFormat(const char * format,ArchiveMode * mode)1211 parseArchiveFormat(const char *format, ArchiveMode *mode)
1212 {
1213 	ArchiveFormat archiveFormat;
1214 
1215 	*mode = archModeWrite;
1216 
1217 	if (pg_strcasecmp(format, "a") == 0 || pg_strcasecmp(format, "append") == 0)
1218 	{
1219 		/* This is used by pg_dumpall, and is not documented */
1220 		archiveFormat = archNull;
1221 		*mode = archModeAppend;
1222 	}
1223 	else if (pg_strcasecmp(format, "c") == 0)
1224 		archiveFormat = archCustom;
1225 	else if (pg_strcasecmp(format, "custom") == 0)
1226 		archiveFormat = archCustom;
1227 	else if (pg_strcasecmp(format, "d") == 0)
1228 		archiveFormat = archDirectory;
1229 	else if (pg_strcasecmp(format, "directory") == 0)
1230 		archiveFormat = archDirectory;
1231 	else if (pg_strcasecmp(format, "p") == 0)
1232 		archiveFormat = archNull;
1233 	else if (pg_strcasecmp(format, "plain") == 0)
1234 		archiveFormat = archNull;
1235 	else if (pg_strcasecmp(format, "t") == 0)
1236 		archiveFormat = archTar;
1237 	else if (pg_strcasecmp(format, "tar") == 0)
1238 		archiveFormat = archTar;
1239 	else
1240 		exit_horribly(NULL, "invalid output format \"%s\" specified\n", format);
1241 	return archiveFormat;
1242 }
1243 
1244 /*
1245  * Find the OIDs of all schemas matching the given list of patterns,
1246  * and append them to the given OID list.
1247  */
1248 static void
expand_schema_name_patterns(Archive * fout,SimpleStringList * patterns,SimpleOidList * oids,bool strict_names)1249 expand_schema_name_patterns(Archive *fout,
1250 							SimpleStringList *patterns,
1251 							SimpleOidList *oids,
1252 							bool strict_names)
1253 {
1254 	PQExpBuffer query;
1255 	PGresult   *res;
1256 	SimpleStringListCell *cell;
1257 	int			i;
1258 
1259 	if (patterns->head == NULL)
1260 		return;					/* nothing to do */
1261 
1262 	query = createPQExpBuffer();
1263 
1264 	/*
1265 	 * The loop below runs multiple SELECTs might sometimes result in
1266 	 * duplicate entries in the OID list, but we don't care.
1267 	 */
1268 
1269 	for (cell = patterns->head; cell; cell = cell->next)
1270 	{
1271 		appendPQExpBuffer(query,
1272 						  "SELECT oid FROM pg_catalog.pg_namespace n\n");
1273 		processSQLNamePattern(GetConnection(fout), query, cell->val, false,
1274 							  false, NULL, "n.nspname", NULL, NULL);
1275 
1276 		res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1277 		if (strict_names && PQntuples(res) == 0)
1278 			exit_horribly(NULL, "no matching schemas were found for pattern \"%s\"\n", cell->val);
1279 
1280 		for (i = 0; i < PQntuples(res); i++)
1281 		{
1282 			simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1283 		}
1284 
1285 		PQclear(res);
1286 		resetPQExpBuffer(query);
1287 	}
1288 
1289 	destroyPQExpBuffer(query);
1290 }
1291 
1292 /*
1293  * Find the OIDs of all tables matching the given list of patterns,
1294  * and append them to the given OID list.
1295  */
1296 static void
expand_table_name_patterns(Archive * fout,SimpleStringList * patterns,SimpleOidList * oids,bool strict_names)1297 expand_table_name_patterns(Archive *fout,
1298 						   SimpleStringList *patterns, SimpleOidList *oids,
1299 						   bool strict_names)
1300 {
1301 	PQExpBuffer query;
1302 	PGresult   *res;
1303 	SimpleStringListCell *cell;
1304 	int			i;
1305 
1306 	if (patterns->head == NULL)
1307 		return;					/* nothing to do */
1308 
1309 	query = createPQExpBuffer();
1310 
1311 	/*
1312 	 * this might sometimes result in duplicate entries in the OID list, but
1313 	 * we don't care.
1314 	 */
1315 
1316 	for (cell = patterns->head; cell; cell = cell->next)
1317 	{
1318 		/*
1319 		 * Query must remain ABSOLUTELY devoid of unqualified names.  This
1320 		 * would be unnecessary given a pg_table_is_visible() variant taking a
1321 		 * search_path argument.
1322 		 */
1323 		appendPQExpBuffer(query,
1324 						  "SELECT c.oid"
1325 						  "\nFROM pg_catalog.pg_class c"
1326 						  "\n     LEFT JOIN pg_catalog.pg_namespace n"
1327 						  "\n     ON n.oid OPERATOR(pg_catalog.=) c.relnamespace"
1328 						  "\nWHERE c.relkind OPERATOR(pg_catalog.=) ANY"
1329 						  "\n    (array['%c', '%c', '%c', '%c', '%c', '%c'])\n",
1330 						  RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW,
1331 						  RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE,
1332 						  RELKIND_PARTITIONED_TABLE);
1333 		processSQLNamePattern(GetConnection(fout), query, cell->val, true,
1334 							  false, "n.nspname", "c.relname", NULL,
1335 							  "pg_catalog.pg_table_is_visible(c.oid)");
1336 
1337 		ExecuteSqlStatement(fout, "RESET search_path");
1338 		res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
1339 		PQclear(ExecuteSqlQueryForSingleRow(fout,
1340 											ALWAYS_SECURE_SEARCH_PATH_SQL));
1341 		if (strict_names && PQntuples(res) == 0)
1342 			exit_horribly(NULL, "no matching tables were found for pattern \"%s\"\n", cell->val);
1343 
1344 		for (i = 0; i < PQntuples(res); i++)
1345 		{
1346 			simple_oid_list_append(oids, atooid(PQgetvalue(res, i, 0)));
1347 		}
1348 
1349 		PQclear(res);
1350 		resetPQExpBuffer(query);
1351 	}
1352 
1353 	destroyPQExpBuffer(query);
1354 }
1355 
1356 /*
1357  * checkExtensionMembership
1358  *		Determine whether object is an extension member, and if so,
1359  *		record an appropriate dependency and set the object's dump flag.
1360  *
1361  * It's important to call this for each object that could be an extension
1362  * member.  Generally, we integrate this with determining the object's
1363  * to-be-dumped-ness, since extension membership overrides other rules for that.
1364  *
1365  * Returns true if object is an extension member, else false.
1366  */
1367 static bool
checkExtensionMembership(DumpableObject * dobj,Archive * fout)1368 checkExtensionMembership(DumpableObject *dobj, Archive *fout)
1369 {
1370 	ExtensionInfo *ext = findOwningExtension(dobj->catId);
1371 
1372 	if (ext == NULL)
1373 		return false;
1374 
1375 	dobj->ext_member = true;
1376 
1377 	/* Record dependency so that getDependencies needn't deal with that */
1378 	addObjectDependency(dobj, ext->dobj.dumpId);
1379 
1380 	/*
1381 	 * In 9.6 and above, mark the member object to have any non-initial ACL,
1382 	 * policies, and security labels dumped.
1383 	 *
1384 	 * Note that any initial ACLs (see pg_init_privs) will be removed when we
1385 	 * extract the information about the object.  We don't provide support for
1386 	 * initial policies and security labels and it seems unlikely for those to
1387 	 * ever exist, but we may have to revisit this later.
1388 	 *
1389 	 * Prior to 9.6, we do not include any extension member components.
1390 	 *
1391 	 * In binary upgrades, we still dump all components of the members
1392 	 * individually, since the idea is to exactly reproduce the database
1393 	 * contents rather than replace the extension contents with something
1394 	 * different.
1395 	 */
1396 	if (fout->dopt->binary_upgrade)
1397 		dobj->dump = ext->dobj.dump;
1398 	else
1399 	{
1400 		if (fout->remoteVersion < 90600)
1401 			dobj->dump = DUMP_COMPONENT_NONE;
1402 		else
1403 			dobj->dump = ext->dobj.dump_contains & (DUMP_COMPONENT_ACL |
1404 													DUMP_COMPONENT_SECLABEL |
1405 													DUMP_COMPONENT_POLICY);
1406 	}
1407 
1408 	return true;
1409 }
1410 
1411 /*
1412  * selectDumpableNamespace: policy-setting subroutine
1413  *		Mark a namespace as to be dumped or not
1414  */
1415 static void
selectDumpableNamespace(NamespaceInfo * nsinfo,Archive * fout)1416 selectDumpableNamespace(NamespaceInfo *nsinfo, Archive *fout)
1417 {
1418 	/*
1419 	 * If specific tables are being dumped, do not dump any complete
1420 	 * namespaces. If specific namespaces are being dumped, dump just those
1421 	 * namespaces. Otherwise, dump all non-system namespaces.
1422 	 */
1423 	if (table_include_oids.head != NULL)
1424 		nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1425 	else if (schema_include_oids.head != NULL)
1426 		nsinfo->dobj.dump_contains = nsinfo->dobj.dump =
1427 			simple_oid_list_member(&schema_include_oids,
1428 								   nsinfo->dobj.catId.oid) ?
1429 			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1430 	else if (fout->remoteVersion >= 90600 &&
1431 			 strcmp(nsinfo->dobj.name, "pg_catalog") == 0)
1432 	{
1433 		/*
1434 		 * In 9.6 and above, we dump out any ACLs defined in pg_catalog, if
1435 		 * they are interesting (and not the original ACLs which were set at
1436 		 * initdb time, see pg_init_privs).
1437 		 */
1438 		nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
1439 	}
1440 	else if (strncmp(nsinfo->dobj.name, "pg_", 3) == 0 ||
1441 			 strcmp(nsinfo->dobj.name, "information_schema") == 0)
1442 	{
1443 		/* Other system schemas don't get dumped */
1444 		nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1445 	}
1446 	else if (strcmp(nsinfo->dobj.name, "public") == 0)
1447 	{
1448 		/*
1449 		 * The public schema is a strange beast that sits in a sort of
1450 		 * no-mans-land between being a system object and a user object.  We
1451 		 * don't want to dump creation or comment commands for it, because
1452 		 * that complicates matters for non-superuser use of pg_dump.  But we
1453 		 * should dump any ACL changes that have occurred for it, and of
1454 		 * course we should dump contained objects.
1455 		 */
1456 		nsinfo->dobj.dump = DUMP_COMPONENT_ACL;
1457 		nsinfo->dobj.dump_contains = DUMP_COMPONENT_ALL;
1458 	}
1459 	else
1460 		nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_ALL;
1461 
1462 	/*
1463 	 * In any case, a namespace can be excluded by an exclusion switch
1464 	 */
1465 	if (nsinfo->dobj.dump_contains &&
1466 		simple_oid_list_member(&schema_exclude_oids,
1467 							   nsinfo->dobj.catId.oid))
1468 		nsinfo->dobj.dump_contains = nsinfo->dobj.dump = DUMP_COMPONENT_NONE;
1469 
1470 	/*
1471 	 * If the schema belongs to an extension, allow extension membership to
1472 	 * override the dump decision for the schema itself.  However, this does
1473 	 * not change dump_contains, so this won't change what we do with objects
1474 	 * within the schema.  (If they belong to the extension, they'll get
1475 	 * suppressed by it, otherwise not.)
1476 	 */
1477 	(void) checkExtensionMembership(&nsinfo->dobj, fout);
1478 }
1479 
1480 /*
1481  * selectDumpableTable: policy-setting subroutine
1482  *		Mark a table as to be dumped or not
1483  */
1484 static void
selectDumpableTable(TableInfo * tbinfo,Archive * fout)1485 selectDumpableTable(TableInfo *tbinfo, Archive *fout)
1486 {
1487 	if (checkExtensionMembership(&tbinfo->dobj, fout))
1488 		return;					/* extension membership overrides all else */
1489 
1490 	/*
1491 	 * If specific tables are being dumped, dump just those tables; else, dump
1492 	 * according to the parent namespace's dump flag.
1493 	 */
1494 	if (table_include_oids.head != NULL)
1495 		tbinfo->dobj.dump = simple_oid_list_member(&table_include_oids,
1496 												   tbinfo->dobj.catId.oid) ?
1497 			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1498 	else
1499 		tbinfo->dobj.dump = tbinfo->dobj.namespace->dobj.dump_contains;
1500 
1501 	/*
1502 	 * In any case, a table can be excluded by an exclusion switch
1503 	 */
1504 	if (tbinfo->dobj.dump &&
1505 		simple_oid_list_member(&table_exclude_oids,
1506 							   tbinfo->dobj.catId.oid))
1507 		tbinfo->dobj.dump = DUMP_COMPONENT_NONE;
1508 }
1509 
1510 /*
1511  * selectDumpableType: policy-setting subroutine
1512  *		Mark a type as to be dumped or not
1513  *
1514  * If it's a table's rowtype or an autogenerated array type, we also apply a
1515  * special type code to facilitate sorting into the desired order.  (We don't
1516  * want to consider those to be ordinary types because that would bring tables
1517  * up into the datatype part of the dump order.)  We still set the object's
1518  * dump flag; that's not going to cause the dummy type to be dumped, but we
1519  * need it so that casts involving such types will be dumped correctly -- see
1520  * dumpCast.  This means the flag should be set the same as for the underlying
1521  * object (the table or base type).
1522  */
1523 static void
selectDumpableType(TypeInfo * tyinfo,Archive * fout)1524 selectDumpableType(TypeInfo *tyinfo, Archive *fout)
1525 {
1526 	/* skip complex types, except for standalone composite types */
1527 	if (OidIsValid(tyinfo->typrelid) &&
1528 		tyinfo->typrelkind != RELKIND_COMPOSITE_TYPE)
1529 	{
1530 		TableInfo  *tytable = findTableByOid(tyinfo->typrelid);
1531 
1532 		tyinfo->dobj.objType = DO_DUMMY_TYPE;
1533 		if (tytable != NULL)
1534 			tyinfo->dobj.dump = tytable->dobj.dump;
1535 		else
1536 			tyinfo->dobj.dump = DUMP_COMPONENT_NONE;
1537 		return;
1538 	}
1539 
1540 	/* skip auto-generated array types */
1541 	if (tyinfo->isArray)
1542 	{
1543 		tyinfo->dobj.objType = DO_DUMMY_TYPE;
1544 
1545 		/*
1546 		 * Fall through to set the dump flag; we assume that the subsequent
1547 		 * rules will do the same thing as they would for the array's base
1548 		 * type.  (We cannot reliably look up the base type here, since
1549 		 * getTypes may not have processed it yet.)
1550 		 */
1551 	}
1552 
1553 	if (checkExtensionMembership(&tyinfo->dobj, fout))
1554 		return;					/* extension membership overrides all else */
1555 
1556 	/* Dump based on if the contents of the namespace are being dumped */
1557 	tyinfo->dobj.dump = tyinfo->dobj.namespace->dobj.dump_contains;
1558 }
1559 
1560 /*
1561  * selectDumpableDefaultACL: policy-setting subroutine
1562  *		Mark a default ACL as to be dumped or not
1563  *
1564  * For per-schema default ACLs, dump if the schema is to be dumped.
1565  * Otherwise dump if we are dumping "everything".  Note that dataOnly
1566  * and aclsSkip are checked separately.
1567  */
1568 static void
selectDumpableDefaultACL(DefaultACLInfo * dinfo,DumpOptions * dopt)1569 selectDumpableDefaultACL(DefaultACLInfo *dinfo, DumpOptions *dopt)
1570 {
1571 	/* Default ACLs can't be extension members */
1572 
1573 	if (dinfo->dobj.namespace)
1574 		/* default ACLs are considered part of the namespace */
1575 		dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump_contains;
1576 	else
1577 		dinfo->dobj.dump = dopt->include_everything ?
1578 			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1579 }
1580 
1581 /*
1582  * selectDumpableCast: policy-setting subroutine
1583  *		Mark a cast as to be dumped or not
1584  *
1585  * Casts do not belong to any particular namespace (since they haven't got
1586  * names), nor do they have identifiable owners.  To distinguish user-defined
1587  * casts from built-in ones, we must resort to checking whether the cast's
1588  * OID is in the range reserved for initdb.
1589  */
1590 static void
selectDumpableCast(CastInfo * cast,Archive * fout)1591 selectDumpableCast(CastInfo *cast, Archive *fout)
1592 {
1593 	if (checkExtensionMembership(&cast->dobj, fout))
1594 		return;					/* extension membership overrides all else */
1595 
1596 	/*
1597 	 * This would be DUMP_COMPONENT_ACL for from-initdb casts, but they do not
1598 	 * support ACLs currently.
1599 	 */
1600 	if (cast->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1601 		cast->dobj.dump = DUMP_COMPONENT_NONE;
1602 	else
1603 		cast->dobj.dump = fout->dopt->include_everything ?
1604 			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1605 }
1606 
1607 /*
1608  * selectDumpableProcLang: policy-setting subroutine
1609  *		Mark a procedural language as to be dumped or not
1610  *
1611  * Procedural languages do not belong to any particular namespace.  To
1612  * identify built-in languages, we must resort to checking whether the
1613  * language's OID is in the range reserved for initdb.
1614  */
1615 static void
selectDumpableProcLang(ProcLangInfo * plang,Archive * fout)1616 selectDumpableProcLang(ProcLangInfo *plang, Archive *fout)
1617 {
1618 	if (checkExtensionMembership(&plang->dobj, fout))
1619 		return;					/* extension membership overrides all else */
1620 
1621 	/*
1622 	 * Only include procedural languages when we are dumping everything.
1623 	 *
1624 	 * For from-initdb procedural languages, only include ACLs, as we do for
1625 	 * the pg_catalog namespace.  We need this because procedural languages do
1626 	 * not live in any namespace.
1627 	 */
1628 	if (!fout->dopt->include_everything)
1629 		plang->dobj.dump = DUMP_COMPONENT_NONE;
1630 	else
1631 	{
1632 		if (plang->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1633 			plang->dobj.dump = fout->remoteVersion < 90600 ?
1634 				DUMP_COMPONENT_NONE : DUMP_COMPONENT_ACL;
1635 		else
1636 			plang->dobj.dump = DUMP_COMPONENT_ALL;
1637 	}
1638 }
1639 
1640 /*
1641  * selectDumpableAccessMethod: policy-setting subroutine
1642  *		Mark an access method as to be dumped or not
1643  *
1644  * Access methods do not belong to any particular namespace.  To identify
1645  * built-in access methods, we must resort to checking whether the
1646  * method's OID is in the range reserved for initdb.
1647  */
1648 static void
selectDumpableAccessMethod(AccessMethodInfo * method,Archive * fout)1649 selectDumpableAccessMethod(AccessMethodInfo *method, Archive *fout)
1650 {
1651 	if (checkExtensionMembership(&method->dobj, fout))
1652 		return;					/* extension membership overrides all else */
1653 
1654 	/*
1655 	 * This would be DUMP_COMPONENT_ACL for from-initdb access methods, but
1656 	 * they do not support ACLs currently.
1657 	 */
1658 	if (method->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1659 		method->dobj.dump = DUMP_COMPONENT_NONE;
1660 	else
1661 		method->dobj.dump = fout->dopt->include_everything ?
1662 			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1663 }
1664 
1665 /*
1666  * selectDumpableExtension: policy-setting subroutine
1667  *		Mark an extension as to be dumped or not
1668  *
1669  * Built-in extensions should be skipped except for checking ACLs, since we
1670  * assume those will already be installed in the target database.  We identify
1671  * such extensions by their having OIDs in the range reserved for initdb.
1672  * We dump all user-added extensions by default, or none of them if
1673  * include_everything is false (i.e., a --schema or --table switch was given).
1674  */
1675 static void
selectDumpableExtension(ExtensionInfo * extinfo,DumpOptions * dopt)1676 selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt)
1677 {
1678 	/*
1679 	 * Use DUMP_COMPONENT_ACL for built-in extensions, to allow users to
1680 	 * change permissions on their member objects, if they wish to, and have
1681 	 * those changes preserved.
1682 	 */
1683 	if (extinfo->dobj.catId.oid <= (Oid) g_last_builtin_oid)
1684 		extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_ACL;
1685 	else
1686 		extinfo->dobj.dump = extinfo->dobj.dump_contains =
1687 			dopt->include_everything ? DUMP_COMPONENT_ALL :
1688 			DUMP_COMPONENT_NONE;
1689 }
1690 
1691 /*
1692  * selectDumpablePublicationTable: policy-setting subroutine
1693  *		Mark a publication table as to be dumped or not
1694  *
1695  * Publication tables have schemas, but those are ignored in decision making,
1696  * because publications are only dumped when we are dumping everything.
1697  */
1698 static void
selectDumpablePublicationTable(DumpableObject * dobj,Archive * fout)1699 selectDumpablePublicationTable(DumpableObject *dobj, Archive *fout)
1700 {
1701 	if (checkExtensionMembership(dobj, fout))
1702 		return;					/* extension membership overrides all else */
1703 
1704 	dobj->dump = fout->dopt->include_everything ?
1705 		DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1706 }
1707 
1708 /*
1709  * selectDumpableObject: policy-setting subroutine
1710  *		Mark a generic dumpable object as to be dumped or not
1711  *
1712  * Use this only for object types without a special-case routine above.
1713  */
1714 static void
selectDumpableObject(DumpableObject * dobj,Archive * fout)1715 selectDumpableObject(DumpableObject *dobj, Archive *fout)
1716 {
1717 	if (checkExtensionMembership(dobj, fout))
1718 		return;					/* extension membership overrides all else */
1719 
1720 	/*
1721 	 * Default policy is to dump if parent namespace is dumpable, or for
1722 	 * non-namespace-associated items, dump if we're dumping "everything".
1723 	 */
1724 	if (dobj->namespace)
1725 		dobj->dump = dobj->namespace->dobj.dump_contains;
1726 	else
1727 		dobj->dump = fout->dopt->include_everything ?
1728 			DUMP_COMPONENT_ALL : DUMP_COMPONENT_NONE;
1729 }
1730 
1731 /*
1732  *	Dump a table's contents for loading using the COPY command
1733  *	- this routine is called by the Archiver when it wants the table
1734  *	  to be dumped.
1735  */
1736 
1737 static int
dumpTableData_copy(Archive * fout,void * dcontext)1738 dumpTableData_copy(Archive *fout, void *dcontext)
1739 {
1740 	TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1741 	TableInfo  *tbinfo = tdinfo->tdtable;
1742 	const char *classname = tbinfo->dobj.name;
1743 	const bool	hasoids = tbinfo->hasoids;
1744 	const bool	oids = tdinfo->oids;
1745 	PQExpBuffer q = createPQExpBuffer();
1746 
1747 	/*
1748 	 * Note: can't use getThreadLocalPQExpBuffer() here, we're calling fmtId
1749 	 * which uses it already.
1750 	 */
1751 	PQExpBuffer clistBuf = createPQExpBuffer();
1752 	PGconn	   *conn = GetConnection(fout);
1753 	PGresult   *res;
1754 	int			ret;
1755 	char	   *copybuf;
1756 	const char *column_list;
1757 
1758 	if (g_verbose)
1759 		write_msg(NULL, "dumping contents of table \"%s.%s\"\n",
1760 				  tbinfo->dobj.namespace->dobj.name, classname);
1761 
1762 	/*
1763 	 * Specify the column list explicitly so that we have no possibility of
1764 	 * retrieving data in the wrong column order.  (The default column
1765 	 * ordering of COPY will not be what we want in certain corner cases
1766 	 * involving ADD COLUMN and inheritance.)
1767 	 */
1768 	column_list = fmtCopyColumnList(tbinfo, clistBuf);
1769 
1770 	if (oids && hasoids)
1771 	{
1772 		appendPQExpBuffer(q, "COPY %s %s WITH OIDS TO stdout;",
1773 						  fmtQualifiedDumpable(tbinfo),
1774 						  column_list);
1775 	}
1776 	else if (tdinfo->filtercond)
1777 	{
1778 		/* Note: this syntax is only supported in 8.2 and up */
1779 		appendPQExpBufferStr(q, "COPY (SELECT ");
1780 		/* klugery to get rid of parens in column list */
1781 		if (strlen(column_list) > 2)
1782 		{
1783 			appendPQExpBufferStr(q, column_list + 1);
1784 			q->data[q->len - 1] = ' ';
1785 		}
1786 		else
1787 			appendPQExpBufferStr(q, "* ");
1788 		appendPQExpBuffer(q, "FROM %s %s) TO stdout;",
1789 						  fmtQualifiedDumpable(tbinfo),
1790 						  tdinfo->filtercond);
1791 	}
1792 	else
1793 	{
1794 		appendPQExpBuffer(q, "COPY %s %s TO stdout;",
1795 						  fmtQualifiedDumpable(tbinfo),
1796 						  column_list);
1797 	}
1798 	res = ExecuteSqlQuery(fout, q->data, PGRES_COPY_OUT);
1799 	PQclear(res);
1800 	destroyPQExpBuffer(clistBuf);
1801 
1802 	for (;;)
1803 	{
1804 		ret = PQgetCopyData(conn, &copybuf, 0);
1805 
1806 		if (ret < 0)
1807 			break;				/* done or error */
1808 
1809 		if (copybuf)
1810 		{
1811 			WriteData(fout, copybuf, ret);
1812 			PQfreemem(copybuf);
1813 		}
1814 
1815 		/* ----------
1816 		 * THROTTLE:
1817 		 *
1818 		 * There was considerable discussion in late July, 2000 regarding
1819 		 * slowing down pg_dump when backing up large tables. Users with both
1820 		 * slow & fast (multi-processor) machines experienced performance
1821 		 * degradation when doing a backup.
1822 		 *
1823 		 * Initial attempts based on sleeping for a number of ms for each ms
1824 		 * of work were deemed too complex, then a simple 'sleep in each loop'
1825 		 * implementation was suggested. The latter failed because the loop
1826 		 * was too tight. Finally, the following was implemented:
1827 		 *
1828 		 * If throttle is non-zero, then
1829 		 *		See how long since the last sleep.
1830 		 *		Work out how long to sleep (based on ratio).
1831 		 *		If sleep is more than 100ms, then
1832 		 *			sleep
1833 		 *			reset timer
1834 		 *		EndIf
1835 		 * EndIf
1836 		 *
1837 		 * where the throttle value was the number of ms to sleep per ms of
1838 		 * work. The calculation was done in each loop.
1839 		 *
1840 		 * Most of the hard work is done in the backend, and this solution
1841 		 * still did not work particularly well: on slow machines, the ratio
1842 		 * was 50:1, and on medium paced machines, 1:1, and on fast
1843 		 * multi-processor machines, it had little or no effect, for reasons
1844 		 * that were unclear.
1845 		 *
1846 		 * Further discussion ensued, and the proposal was dropped.
1847 		 *
1848 		 * For those people who want this feature, it can be implemented using
1849 		 * gettimeofday in each loop, calculating the time since last sleep,
1850 		 * multiplying that by the sleep ratio, then if the result is more
1851 		 * than a preset 'minimum sleep time' (say 100ms), call the 'select'
1852 		 * function to sleep for a subsecond period ie.
1853 		 *
1854 		 * select(0, NULL, NULL, NULL, &tvi);
1855 		 *
1856 		 * This will return after the interval specified in the structure tvi.
1857 		 * Finally, call gettimeofday again to save the 'last sleep time'.
1858 		 * ----------
1859 		 */
1860 	}
1861 	archprintf(fout, "\\.\n\n\n");
1862 
1863 	if (ret == -2)
1864 	{
1865 		/* copy data transfer failed */
1866 		write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetCopyData() failed.\n", classname);
1867 		write_msg(NULL, "Error message from server: %s", PQerrorMessage(conn));
1868 		write_msg(NULL, "The command was: %s\n", q->data);
1869 		exit_nicely(1);
1870 	}
1871 
1872 	/* Check command status and return to normal libpq state */
1873 	res = PQgetResult(conn);
1874 	if (PQresultStatus(res) != PGRES_COMMAND_OK)
1875 	{
1876 		write_msg(NULL, "Dumping the contents of table \"%s\" failed: PQgetResult() failed.\n", classname);
1877 		write_msg(NULL, "Error message from server: %s", PQerrorMessage(conn));
1878 		write_msg(NULL, "The command was: %s\n", q->data);
1879 		exit_nicely(1);
1880 	}
1881 	PQclear(res);
1882 
1883 	/* Do this to ensure we've pumped libpq back to idle state */
1884 	if (PQgetResult(conn) != NULL)
1885 		write_msg(NULL, "WARNING: unexpected extra results during COPY of table \"%s\"\n",
1886 				  classname);
1887 
1888 	destroyPQExpBuffer(q);
1889 	return 1;
1890 }
1891 
1892 /*
1893  * Dump table data using INSERT commands.
1894  *
1895  * Caution: when we restore from an archive file direct to database, the
1896  * INSERT commands emitted by this function have to be parsed by
1897  * pg_backup_db.c's ExecuteSimpleCommands(), which will not handle comments,
1898  * E'' strings, or dollar-quoted strings.  So don't emit anything like that.
1899  */
1900 static int
dumpTableData_insert(Archive * fout,void * dcontext)1901 dumpTableData_insert(Archive *fout, void *dcontext)
1902 {
1903 	TableDataInfo *tdinfo = (TableDataInfo *) dcontext;
1904 	TableInfo  *tbinfo = tdinfo->tdtable;
1905 	DumpOptions *dopt = fout->dopt;
1906 	PQExpBuffer q = createPQExpBuffer();
1907 	PQExpBuffer insertStmt = NULL;
1908 	PGresult   *res;
1909 	int			tuple;
1910 	int			nfields;
1911 	int			field;
1912 
1913 	appendPQExpBuffer(q, "DECLARE _pg_dump_cursor CURSOR FOR "
1914 					  "SELECT * FROM ONLY %s",
1915 					  fmtQualifiedDumpable(tbinfo));
1916 	if (tdinfo->filtercond)
1917 		appendPQExpBuffer(q, " %s", tdinfo->filtercond);
1918 
1919 	ExecuteSqlStatement(fout, q->data);
1920 
1921 	while (1)
1922 	{
1923 		res = ExecuteSqlQuery(fout, "FETCH 100 FROM _pg_dump_cursor",
1924 							  PGRES_TUPLES_OK);
1925 		nfields = PQnfields(res);
1926 		for (tuple = 0; tuple < PQntuples(res); tuple++)
1927 		{
1928 			/*
1929 			 * First time through, we build as much of the INSERT statement as
1930 			 * possible in "insertStmt", which we can then just print for each
1931 			 * line. If the table happens to have zero columns then this will
1932 			 * be a complete statement, otherwise it will end in "VALUES(" and
1933 			 * be ready to have the row's column values appended.
1934 			 */
1935 			if (insertStmt == NULL)
1936 			{
1937 				TableInfo  *targettab;
1938 
1939 				insertStmt = createPQExpBuffer();
1940 
1941 				/*
1942 				 * When load-via-partition-root is set, get the root table
1943 				 * name for the partition table, so that we can reload data
1944 				 * through the root table.
1945 				 */
1946 				if (dopt->load_via_partition_root && tbinfo->ispartition)
1947 					targettab = getRootTableInfo(tbinfo);
1948 				else
1949 					targettab = tbinfo;
1950 
1951 				appendPQExpBuffer(insertStmt, "INSERT INTO %s ",
1952 								  fmtQualifiedDumpable(targettab));
1953 
1954 				/* corner case for zero-column table */
1955 				if (nfields == 0)
1956 				{
1957 					appendPQExpBufferStr(insertStmt, "DEFAULT VALUES;\n");
1958 				}
1959 				else
1960 				{
1961 					/* append the list of column names if required */
1962 					if (dopt->column_inserts)
1963 					{
1964 						appendPQExpBufferChar(insertStmt, '(');
1965 						for (field = 0; field < nfields; field++)
1966 						{
1967 							if (field > 0)
1968 								appendPQExpBufferStr(insertStmt, ", ");
1969 							appendPQExpBufferStr(insertStmt,
1970 												 fmtId(PQfname(res, field)));
1971 						}
1972 						appendPQExpBufferStr(insertStmt, ") ");
1973 					}
1974 
1975 					if (tbinfo->needs_override)
1976 						appendPQExpBufferStr(insertStmt, "OVERRIDING SYSTEM VALUE ");
1977 
1978 					appendPQExpBufferStr(insertStmt, "VALUES (");
1979 				}
1980 			}
1981 
1982 			archputs(insertStmt->data, fout);
1983 
1984 			/* if it is zero-column table then we're done */
1985 			if (nfields == 0)
1986 				continue;
1987 
1988 			for (field = 0; field < nfields; field++)
1989 			{
1990 				if (field > 0)
1991 					archputs(", ", fout);
1992 				if (PQgetisnull(res, tuple, field))
1993 				{
1994 					archputs("NULL", fout);
1995 					continue;
1996 				}
1997 
1998 				/* XXX This code is partially duplicated in ruleutils.c */
1999 				switch (PQftype(res, field))
2000 				{
2001 					case INT2OID:
2002 					case INT4OID:
2003 					case INT8OID:
2004 					case OIDOID:
2005 					case FLOAT4OID:
2006 					case FLOAT8OID:
2007 					case NUMERICOID:
2008 						{
2009 							/*
2010 							 * These types are printed without quotes unless
2011 							 * they contain values that aren't accepted by the
2012 							 * scanner unquoted (e.g., 'NaN').  Note that
2013 							 * strtod() and friends might accept NaN, so we
2014 							 * can't use that to test.
2015 							 *
2016 							 * In reality we only need to defend against
2017 							 * infinity and NaN, so we need not get too crazy
2018 							 * about pattern matching here.
2019 							 */
2020 							const char *s = PQgetvalue(res, tuple, field);
2021 
2022 							if (strspn(s, "0123456789 +-eE.") == strlen(s))
2023 								archputs(s, fout);
2024 							else
2025 								archprintf(fout, "'%s'", s);
2026 						}
2027 						break;
2028 
2029 					case BITOID:
2030 					case VARBITOID:
2031 						archprintf(fout, "B'%s'",
2032 								   PQgetvalue(res, tuple, field));
2033 						break;
2034 
2035 					case BOOLOID:
2036 						if (strcmp(PQgetvalue(res, tuple, field), "t") == 0)
2037 							archputs("true", fout);
2038 						else
2039 							archputs("false", fout);
2040 						break;
2041 
2042 					default:
2043 						/* All other types are printed as string literals. */
2044 						resetPQExpBuffer(q);
2045 						appendStringLiteralAH(q,
2046 											  PQgetvalue(res, tuple, field),
2047 											  fout);
2048 						archputs(q->data, fout);
2049 						break;
2050 				}
2051 			}
2052 			archputs(");\n", fout);
2053 		}
2054 
2055 		if (PQntuples(res) <= 0)
2056 		{
2057 			PQclear(res);
2058 			break;
2059 		}
2060 		PQclear(res);
2061 	}
2062 
2063 	archputs("\n\n", fout);
2064 
2065 	ExecuteSqlStatement(fout, "CLOSE _pg_dump_cursor");
2066 
2067 	destroyPQExpBuffer(q);
2068 	if (insertStmt != NULL)
2069 		destroyPQExpBuffer(insertStmt);
2070 
2071 	return 1;
2072 }
2073 
2074 /*
2075  * getRootTableInfo:
2076  *     get the root TableInfo for the given partition table.
2077  */
2078 static TableInfo *
getRootTableInfo(TableInfo * tbinfo)2079 getRootTableInfo(TableInfo *tbinfo)
2080 {
2081 	TableInfo  *parentTbinfo;
2082 
2083 	Assert(tbinfo->ispartition);
2084 	Assert(tbinfo->numParents == 1);
2085 
2086 	parentTbinfo = tbinfo->parents[0];
2087 	while (parentTbinfo->ispartition)
2088 	{
2089 		Assert(parentTbinfo->numParents == 1);
2090 		parentTbinfo = parentTbinfo->parents[0];
2091 	}
2092 
2093 	return parentTbinfo;
2094 }
2095 
2096 /*
2097  * dumpTableData -
2098  *	  dump the contents of a single table
2099  *
2100  * Actually, this just makes an ArchiveEntry for the table contents.
2101  */
2102 static void
dumpTableData(Archive * fout,TableDataInfo * tdinfo)2103 dumpTableData(Archive *fout, TableDataInfo *tdinfo)
2104 {
2105 	DumpOptions *dopt = fout->dopt;
2106 	TableInfo  *tbinfo = tdinfo->tdtable;
2107 	PQExpBuffer copyBuf = createPQExpBuffer();
2108 	PQExpBuffer clistBuf = createPQExpBuffer();
2109 	DataDumperPtr dumpFn;
2110 	char	   *copyStmt;
2111 	const char *copyFrom;
2112 
2113 	/* We had better have loaded per-column details about this table */
2114 	Assert(tbinfo->interesting);
2115 
2116 	if (!dopt->dump_inserts)
2117 	{
2118 		/* Dump/restore using COPY */
2119 		dumpFn = dumpTableData_copy;
2120 
2121 		/*
2122 		 * When load-via-partition-root is set, get the root table name for
2123 		 * the partition table, so that we can reload data through the root
2124 		 * table.
2125 		 */
2126 		if (dopt->load_via_partition_root && tbinfo->ispartition)
2127 		{
2128 			TableInfo  *parentTbinfo;
2129 
2130 			parentTbinfo = getRootTableInfo(tbinfo);
2131 			copyFrom = fmtQualifiedDumpable(parentTbinfo);
2132 		}
2133 		else
2134 			copyFrom = fmtQualifiedDumpable(tbinfo);
2135 
2136 		/* must use 2 steps here 'cause fmtId is nonreentrant */
2137 		appendPQExpBuffer(copyBuf, "COPY %s ",
2138 						  copyFrom);
2139 		appendPQExpBuffer(copyBuf, "%s %sFROM stdin;\n",
2140 						  fmtCopyColumnList(tbinfo, clistBuf),
2141 						  (tdinfo->oids && tbinfo->hasoids) ? "WITH OIDS " : "");
2142 		copyStmt = copyBuf->data;
2143 	}
2144 	else
2145 	{
2146 		/* Restore using INSERT */
2147 		dumpFn = dumpTableData_insert;
2148 		copyStmt = NULL;
2149 	}
2150 
2151 	/*
2152 	 * Note: although the TableDataInfo is a full DumpableObject, we treat its
2153 	 * dependency on its table as "special" and pass it to ArchiveEntry now.
2154 	 * See comments for BuildArchiveDependencies.
2155 	 */
2156 	if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
2157 		ArchiveEntry(fout, tdinfo->dobj.catId, tdinfo->dobj.dumpId,
2158 					 tbinfo->dobj.name, tbinfo->dobj.namespace->dobj.name,
2159 					 NULL, tbinfo->rolname,
2160 					 false, "TABLE DATA", SECTION_DATA,
2161 					 "", "", copyStmt,
2162 					 &(tbinfo->dobj.dumpId), 1,
2163 					 dumpFn, tdinfo);
2164 
2165 	destroyPQExpBuffer(copyBuf);
2166 	destroyPQExpBuffer(clistBuf);
2167 }
2168 
2169 /*
2170  * refreshMatViewData -
2171  *	  load or refresh the contents of a single materialized view
2172  *
2173  * Actually, this just makes an ArchiveEntry for the REFRESH MATERIALIZED VIEW
2174  * statement.
2175  */
2176 static void
refreshMatViewData(Archive * fout,TableDataInfo * tdinfo)2177 refreshMatViewData(Archive *fout, TableDataInfo *tdinfo)
2178 {
2179 	TableInfo  *tbinfo = tdinfo->tdtable;
2180 	PQExpBuffer q;
2181 
2182 	/* If the materialized view is not flagged as populated, skip this. */
2183 	if (!tbinfo->relispopulated)
2184 		return;
2185 
2186 	q = createPQExpBuffer();
2187 
2188 	appendPQExpBuffer(q, "REFRESH MATERIALIZED VIEW %s;\n",
2189 					  fmtQualifiedDumpable(tbinfo));
2190 
2191 	if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
2192 		ArchiveEntry(fout,
2193 					 tdinfo->dobj.catId,	/* catalog ID */
2194 					 tdinfo->dobj.dumpId,	/* dump ID */
2195 					 tbinfo->dobj.name, /* Name */
2196 					 tbinfo->dobj.namespace->dobj.name, /* Namespace */
2197 					 NULL,		/* Tablespace */
2198 					 tbinfo->rolname,	/* Owner */
2199 					 false,		/* with oids */
2200 					 "MATERIALIZED VIEW DATA",	/* Desc */
2201 					 SECTION_POST_DATA, /* Section */
2202 					 q->data,	/* Create */
2203 					 "",		/* Del */
2204 					 NULL,		/* Copy */
2205 					 tdinfo->dobj.dependencies, /* Deps */
2206 					 tdinfo->dobj.nDeps,	/* # Deps */
2207 					 NULL,		/* Dumper */
2208 					 NULL);		/* Dumper Arg */
2209 
2210 	destroyPQExpBuffer(q);
2211 }
2212 
2213 /*
2214  * getTableData -
2215  *	  set up dumpable objects representing the contents of tables
2216  */
2217 static void
getTableData(DumpOptions * dopt,TableInfo * tblinfo,int numTables,bool oids,char relkind)2218 getTableData(DumpOptions *dopt, TableInfo *tblinfo, int numTables, bool oids, char relkind)
2219 {
2220 	int			i;
2221 
2222 	for (i = 0; i < numTables; i++)
2223 	{
2224 		if (tblinfo[i].dobj.dump & DUMP_COMPONENT_DATA &&
2225 			(!relkind || tblinfo[i].relkind == relkind))
2226 			makeTableDataInfo(dopt, &(tblinfo[i]), oids);
2227 	}
2228 }
2229 
2230 /*
2231  * Make a dumpable object for the data of this specific table
2232  *
2233  * Note: we make a TableDataInfo if and only if we are going to dump the
2234  * table data; the "dump" flag in such objects isn't used.
2235  */
2236 static void
makeTableDataInfo(DumpOptions * dopt,TableInfo * tbinfo,bool oids)2237 makeTableDataInfo(DumpOptions *dopt, TableInfo *tbinfo, bool oids)
2238 {
2239 	TableDataInfo *tdinfo;
2240 
2241 	/*
2242 	 * Nothing to do if we already decided to dump the table.  This will
2243 	 * happen for "config" tables.
2244 	 */
2245 	if (tbinfo->dataObj != NULL)
2246 		return;
2247 
2248 	/* Skip VIEWs (no data to dump) */
2249 	if (tbinfo->relkind == RELKIND_VIEW)
2250 		return;
2251 	/* Skip FOREIGN TABLEs (no data to dump) */
2252 	if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
2253 		return;
2254 	/* Skip partitioned tables (data in partitions) */
2255 	if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
2256 		return;
2257 
2258 	/* Don't dump data in unlogged tables, if so requested */
2259 	if (tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED &&
2260 		dopt->no_unlogged_table_data)
2261 		return;
2262 
2263 	/* Check that the data is not explicitly excluded */
2264 	if (simple_oid_list_member(&tabledata_exclude_oids,
2265 							   tbinfo->dobj.catId.oid))
2266 		return;
2267 
2268 	/* OK, let's dump it */
2269 	tdinfo = (TableDataInfo *) pg_malloc(sizeof(TableDataInfo));
2270 
2271 	if (tbinfo->relkind == RELKIND_MATVIEW)
2272 		tdinfo->dobj.objType = DO_REFRESH_MATVIEW;
2273 	else if (tbinfo->relkind == RELKIND_SEQUENCE)
2274 		tdinfo->dobj.objType = DO_SEQUENCE_SET;
2275 	else
2276 		tdinfo->dobj.objType = DO_TABLE_DATA;
2277 
2278 	/*
2279 	 * Note: use tableoid 0 so that this object won't be mistaken for
2280 	 * something that pg_depend entries apply to.
2281 	 */
2282 	tdinfo->dobj.catId.tableoid = 0;
2283 	tdinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
2284 	AssignDumpId(&tdinfo->dobj);
2285 	tdinfo->dobj.name = tbinfo->dobj.name;
2286 	tdinfo->dobj.namespace = tbinfo->dobj.namespace;
2287 	tdinfo->tdtable = tbinfo;
2288 	tdinfo->oids = oids;
2289 	tdinfo->filtercond = NULL;	/* might get set later */
2290 	addObjectDependency(&tdinfo->dobj, tbinfo->dobj.dumpId);
2291 
2292 	tbinfo->dataObj = tdinfo;
2293 
2294 	/* Make sure that we'll collect per-column info for this table. */
2295 	tbinfo->interesting = true;
2296 }
2297 
2298 /*
2299  * The refresh for a materialized view must be dependent on the refresh for
2300  * any materialized view that this one is dependent on.
2301  *
2302  * This must be called after all the objects are created, but before they are
2303  * sorted.
2304  */
2305 static void
buildMatViewRefreshDependencies(Archive * fout)2306 buildMatViewRefreshDependencies(Archive *fout)
2307 {
2308 	PQExpBuffer query;
2309 	PGresult   *res;
2310 	int			ntups,
2311 				i;
2312 	int			i_classid,
2313 				i_objid,
2314 				i_refobjid;
2315 
2316 	/* No Mat Views before 9.3. */
2317 	if (fout->remoteVersion < 90300)
2318 		return;
2319 
2320 	query = createPQExpBuffer();
2321 
2322 	appendPQExpBufferStr(query, "WITH RECURSIVE w AS "
2323 						 "( "
2324 						 "SELECT d1.objid, d2.refobjid, c2.relkind AS refrelkind "
2325 						 "FROM pg_depend d1 "
2326 						 "JOIN pg_class c1 ON c1.oid = d1.objid "
2327 						 "AND c1.relkind = " CppAsString2(RELKIND_MATVIEW)
2328 						 " JOIN pg_rewrite r1 ON r1.ev_class = d1.objid "
2329 						 "JOIN pg_depend d2 ON d2.classid = 'pg_rewrite'::regclass "
2330 						 "AND d2.objid = r1.oid "
2331 						 "AND d2.refobjid <> d1.objid "
2332 						 "JOIN pg_class c2 ON c2.oid = d2.refobjid "
2333 						 "AND c2.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
2334 						 CppAsString2(RELKIND_VIEW) ") "
2335 						 "WHERE d1.classid = 'pg_class'::regclass "
2336 						 "UNION "
2337 						 "SELECT w.objid, d3.refobjid, c3.relkind "
2338 						 "FROM w "
2339 						 "JOIN pg_rewrite r3 ON r3.ev_class = w.refobjid "
2340 						 "JOIN pg_depend d3 ON d3.classid = 'pg_rewrite'::regclass "
2341 						 "AND d3.objid = r3.oid "
2342 						 "AND d3.refobjid <> w.refobjid "
2343 						 "JOIN pg_class c3 ON c3.oid = d3.refobjid "
2344 						 "AND c3.relkind IN (" CppAsString2(RELKIND_MATVIEW) ","
2345 						 CppAsString2(RELKIND_VIEW) ") "
2346 						 ") "
2347 						 "SELECT 'pg_class'::regclass::oid AS classid, objid, refobjid "
2348 						 "FROM w "
2349 						 "WHERE refrelkind = " CppAsString2(RELKIND_MATVIEW));
2350 
2351 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
2352 
2353 	ntups = PQntuples(res);
2354 
2355 	i_classid = PQfnumber(res, "classid");
2356 	i_objid = PQfnumber(res, "objid");
2357 	i_refobjid = PQfnumber(res, "refobjid");
2358 
2359 	for (i = 0; i < ntups; i++)
2360 	{
2361 		CatalogId	objId;
2362 		CatalogId	refobjId;
2363 		DumpableObject *dobj;
2364 		DumpableObject *refdobj;
2365 		TableInfo  *tbinfo;
2366 		TableInfo  *reftbinfo;
2367 
2368 		objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
2369 		objId.oid = atooid(PQgetvalue(res, i, i_objid));
2370 		refobjId.tableoid = objId.tableoid;
2371 		refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
2372 
2373 		dobj = findObjectByCatalogId(objId);
2374 		if (dobj == NULL)
2375 			continue;
2376 
2377 		Assert(dobj->objType == DO_TABLE);
2378 		tbinfo = (TableInfo *) dobj;
2379 		Assert(tbinfo->relkind == RELKIND_MATVIEW);
2380 		dobj = (DumpableObject *) tbinfo->dataObj;
2381 		if (dobj == NULL)
2382 			continue;
2383 		Assert(dobj->objType == DO_REFRESH_MATVIEW);
2384 
2385 		refdobj = findObjectByCatalogId(refobjId);
2386 		if (refdobj == NULL)
2387 			continue;
2388 
2389 		Assert(refdobj->objType == DO_TABLE);
2390 		reftbinfo = (TableInfo *) refdobj;
2391 		Assert(reftbinfo->relkind == RELKIND_MATVIEW);
2392 		refdobj = (DumpableObject *) reftbinfo->dataObj;
2393 		if (refdobj == NULL)
2394 			continue;
2395 		Assert(refdobj->objType == DO_REFRESH_MATVIEW);
2396 
2397 		addObjectDependency(dobj, refdobj->dumpId);
2398 
2399 		if (!reftbinfo->relispopulated)
2400 			tbinfo->relispopulated = false;
2401 	}
2402 
2403 	PQclear(res);
2404 
2405 	destroyPQExpBuffer(query);
2406 }
2407 
2408 /*
2409  * getTableDataFKConstraints -
2410  *	  add dump-order dependencies reflecting foreign key constraints
2411  *
2412  * This code is executed only in a data-only dump --- in schema+data dumps
2413  * we handle foreign key issues by not creating the FK constraints until
2414  * after the data is loaded.  In a data-only dump, however, we want to
2415  * order the table data objects in such a way that a table's referenced
2416  * tables are restored first.  (In the presence of circular references or
2417  * self-references this may be impossible; we'll detect and complain about
2418  * that during the dependency sorting step.)
2419  */
2420 static void
getTableDataFKConstraints(void)2421 getTableDataFKConstraints(void)
2422 {
2423 	DumpableObject **dobjs;
2424 	int			numObjs;
2425 	int			i;
2426 
2427 	/* Search through all the dumpable objects for FK constraints */
2428 	getDumpableObjects(&dobjs, &numObjs);
2429 	for (i = 0; i < numObjs; i++)
2430 	{
2431 		if (dobjs[i]->objType == DO_FK_CONSTRAINT)
2432 		{
2433 			ConstraintInfo *cinfo = (ConstraintInfo *) dobjs[i];
2434 			TableInfo  *ftable;
2435 
2436 			/* Not interesting unless both tables are to be dumped */
2437 			if (cinfo->contable == NULL ||
2438 				cinfo->contable->dataObj == NULL)
2439 				continue;
2440 			ftable = findTableByOid(cinfo->confrelid);
2441 			if (ftable == NULL ||
2442 				ftable->dataObj == NULL)
2443 				continue;
2444 
2445 			/*
2446 			 * Okay, make referencing table's TABLE_DATA object depend on the
2447 			 * referenced table's TABLE_DATA object.
2448 			 */
2449 			addObjectDependency(&cinfo->contable->dataObj->dobj,
2450 								ftable->dataObj->dobj.dumpId);
2451 		}
2452 	}
2453 	free(dobjs);
2454 }
2455 
2456 
2457 /*
2458  * guessConstraintInheritance:
2459  *	In pre-8.4 databases, we can't tell for certain which constraints
2460  *	are inherited.  We assume a CHECK constraint is inherited if its name
2461  *	matches the name of any constraint in the parent.  Originally this code
2462  *	tried to compare the expression texts, but that can fail for various
2463  *	reasons --- for example, if the parent and child tables are in different
2464  *	schemas, reverse-listing of function calls may produce different text
2465  *	(schema-qualified or not) depending on search path.
2466  *
2467  *	In 8.4 and up we can rely on the conislocal field to decide which
2468  *	constraints must be dumped; much safer.
2469  *
2470  *	This function assumes all conislocal flags were initialized to true.
2471  *	It clears the flag on anything that seems to be inherited.
2472  */
2473 static void
guessConstraintInheritance(TableInfo * tblinfo,int numTables)2474 guessConstraintInheritance(TableInfo *tblinfo, int numTables)
2475 {
2476 	int			i,
2477 				j,
2478 				k;
2479 
2480 	for (i = 0; i < numTables; i++)
2481 	{
2482 		TableInfo  *tbinfo = &(tblinfo[i]);
2483 		int			numParents;
2484 		TableInfo **parents;
2485 		TableInfo  *parent;
2486 
2487 		/* Sequences and views never have parents */
2488 		if (tbinfo->relkind == RELKIND_SEQUENCE ||
2489 			tbinfo->relkind == RELKIND_VIEW)
2490 			continue;
2491 
2492 		/* Don't bother computing anything for non-target tables, either */
2493 		if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
2494 			continue;
2495 
2496 		numParents = tbinfo->numParents;
2497 		parents = tbinfo->parents;
2498 
2499 		if (numParents == 0)
2500 			continue;			/* nothing to see here, move along */
2501 
2502 		/* scan for inherited CHECK constraints */
2503 		for (j = 0; j < tbinfo->ncheck; j++)
2504 		{
2505 			ConstraintInfo *constr;
2506 
2507 			constr = &(tbinfo->checkexprs[j]);
2508 
2509 			for (k = 0; k < numParents; k++)
2510 			{
2511 				int			l;
2512 
2513 				parent = parents[k];
2514 				for (l = 0; l < parent->ncheck; l++)
2515 				{
2516 					ConstraintInfo *pconstr = &(parent->checkexprs[l]);
2517 
2518 					if (strcmp(pconstr->dobj.name, constr->dobj.name) == 0)
2519 					{
2520 						constr->conislocal = false;
2521 						break;
2522 					}
2523 				}
2524 				if (!constr->conislocal)
2525 					break;
2526 			}
2527 		}
2528 	}
2529 }
2530 
2531 
2532 /*
2533  * dumpDatabase:
2534  *	dump the database definition
2535  */
2536 static void
dumpDatabase(Archive * fout)2537 dumpDatabase(Archive *fout)
2538 {
2539 	DumpOptions *dopt = fout->dopt;
2540 	PQExpBuffer dbQry = createPQExpBuffer();
2541 	PQExpBuffer delQry = createPQExpBuffer();
2542 	PQExpBuffer creaQry = createPQExpBuffer();
2543 	PQExpBuffer labelq = createPQExpBuffer();
2544 	PGconn	   *conn = GetConnection(fout);
2545 	PGresult   *res;
2546 	int			i_tableoid,
2547 				i_oid,
2548 				i_datname,
2549 				i_dba,
2550 				i_encoding,
2551 				i_collate,
2552 				i_ctype,
2553 				i_frozenxid,
2554 				i_minmxid,
2555 				i_datacl,
2556 				i_rdatacl,
2557 				i_datistemplate,
2558 				i_datconnlimit,
2559 				i_tablespace;
2560 	CatalogId	dbCatId;
2561 	DumpId		dbDumpId;
2562 	const char *datname,
2563 			   *dba,
2564 			   *encoding,
2565 			   *collate,
2566 			   *ctype,
2567 			   *datacl,
2568 			   *rdatacl,
2569 			   *datistemplate,
2570 			   *datconnlimit,
2571 			   *tablespace;
2572 	uint32		frozenxid,
2573 				minmxid;
2574 	char	   *qdatname;
2575 
2576 	if (g_verbose)
2577 		write_msg(NULL, "saving database definition\n");
2578 
2579 	/*
2580 	 * Fetch the database-level properties for this database.
2581 	 *
2582 	 * The order in which privileges are in the ACL string (the order they
2583 	 * have been GRANT'd in, which the backend maintains) must be preserved to
2584 	 * ensure that GRANTs WITH GRANT OPTION and subsequent GRANTs based on
2585 	 * those are dumped in the correct order.  Note that initial privileges
2586 	 * (pg_init_privs) are not supported on databases, so this logic cannot
2587 	 * make use of buildACLQueries().
2588 	 */
2589 	if (fout->remoteVersion >= 90600)
2590 	{
2591 		appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
2592 						  "(%s datdba) AS dba, "
2593 						  "pg_encoding_to_char(encoding) AS encoding, "
2594 						  "datcollate, datctype, datfrozenxid, datminmxid, "
2595 						  "(SELECT array_agg(acl ORDER BY row_n) FROM "
2596 						  "  (SELECT acl, row_n FROM "
2597 						  "     unnest(coalesce(datacl,acldefault('d',datdba))) "
2598 						  "     WITH ORDINALITY AS perm(acl,row_n) "
2599 						  "   WHERE NOT EXISTS ( "
2600 						  "     SELECT 1 "
2601 						  "     FROM unnest(acldefault('d',datdba)) "
2602 						  "       AS init(init_acl) "
2603 						  "     WHERE acl = init_acl)) AS datacls) "
2604 						  " AS datacl, "
2605 						  "(SELECT array_agg(acl ORDER BY row_n) FROM "
2606 						  "  (SELECT acl, row_n FROM "
2607 						  "     unnest(acldefault('d',datdba)) "
2608 						  "     WITH ORDINALITY AS initp(acl,row_n) "
2609 						  "   WHERE NOT EXISTS ( "
2610 						  "     SELECT 1 "
2611 						  "     FROM unnest(coalesce(datacl,acldefault('d',datdba))) "
2612 						  "       AS permp(orig_acl) "
2613 						  "     WHERE acl = orig_acl)) AS rdatacls) "
2614 						  " AS rdatacl, "
2615 						  "datistemplate, datconnlimit, "
2616 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2617 						  "shobj_description(oid, 'pg_database') AS description "
2618 
2619 						  "FROM pg_database "
2620 						  "WHERE datname = current_database()",
2621 						  username_subquery);
2622 	}
2623 	else if (fout->remoteVersion >= 90300)
2624 	{
2625 		appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
2626 						  "(%s datdba) AS dba, "
2627 						  "pg_encoding_to_char(encoding) AS encoding, "
2628 						  "datcollate, datctype, datfrozenxid, datminmxid, "
2629 						  "datacl, '' as rdatacl, datistemplate, datconnlimit, "
2630 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2631 						  "shobj_description(oid, 'pg_database') AS description "
2632 
2633 						  "FROM pg_database "
2634 						  "WHERE datname = current_database()",
2635 						  username_subquery);
2636 	}
2637 	else if (fout->remoteVersion >= 80400)
2638 	{
2639 		appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
2640 						  "(%s datdba) AS dba, "
2641 						  "pg_encoding_to_char(encoding) AS encoding, "
2642 						  "datcollate, datctype, datfrozenxid, 0 AS datminmxid, "
2643 						  "datacl, '' as rdatacl, datistemplate, datconnlimit, "
2644 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2645 						  "shobj_description(oid, 'pg_database') AS description "
2646 
2647 						  "FROM pg_database "
2648 						  "WHERE datname = current_database()",
2649 						  username_subquery);
2650 	}
2651 	else if (fout->remoteVersion >= 80200)
2652 	{
2653 		appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
2654 						  "(%s datdba) AS dba, "
2655 						  "pg_encoding_to_char(encoding) AS encoding, "
2656 						  "NULL AS datcollate, NULL AS datctype, datfrozenxid, 0 AS datminmxid, "
2657 						  "datacl, '' as rdatacl, datistemplate, datconnlimit, "
2658 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace, "
2659 						  "shobj_description(oid, 'pg_database') AS description "
2660 
2661 						  "FROM pg_database "
2662 						  "WHERE datname = current_database()",
2663 						  username_subquery);
2664 	}
2665 	else
2666 	{
2667 		appendPQExpBuffer(dbQry, "SELECT tableoid, oid, datname, "
2668 						  "(%s datdba) AS dba, "
2669 						  "pg_encoding_to_char(encoding) AS encoding, "
2670 						  "NULL AS datcollate, NULL AS datctype, datfrozenxid, 0 AS datminmxid, "
2671 						  "datacl, '' as rdatacl, datistemplate, "
2672 						  "-1 as datconnlimit, "
2673 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) AS tablespace "
2674 						  "FROM pg_database "
2675 						  "WHERE datname = current_database()",
2676 						  username_subquery);
2677 	}
2678 
2679 	res = ExecuteSqlQueryForSingleRow(fout, dbQry->data);
2680 
2681 	i_tableoid = PQfnumber(res, "tableoid");
2682 	i_oid = PQfnumber(res, "oid");
2683 	i_datname = PQfnumber(res, "datname");
2684 	i_dba = PQfnumber(res, "dba");
2685 	i_encoding = PQfnumber(res, "encoding");
2686 	i_collate = PQfnumber(res, "datcollate");
2687 	i_ctype = PQfnumber(res, "datctype");
2688 	i_frozenxid = PQfnumber(res, "datfrozenxid");
2689 	i_minmxid = PQfnumber(res, "datminmxid");
2690 	i_datacl = PQfnumber(res, "datacl");
2691 	i_rdatacl = PQfnumber(res, "rdatacl");
2692 	i_datistemplate = PQfnumber(res, "datistemplate");
2693 	i_datconnlimit = PQfnumber(res, "datconnlimit");
2694 	i_tablespace = PQfnumber(res, "tablespace");
2695 
2696 	dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
2697 	dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
2698 	datname = PQgetvalue(res, 0, i_datname);
2699 	dba = PQgetvalue(res, 0, i_dba);
2700 	encoding = PQgetvalue(res, 0, i_encoding);
2701 	collate = PQgetvalue(res, 0, i_collate);
2702 	ctype = PQgetvalue(res, 0, i_ctype);
2703 	frozenxid = atooid(PQgetvalue(res, 0, i_frozenxid));
2704 	minmxid = atooid(PQgetvalue(res, 0, i_minmxid));
2705 	datacl = PQgetvalue(res, 0, i_datacl);
2706 	rdatacl = PQgetvalue(res, 0, i_rdatacl);
2707 	datistemplate = PQgetvalue(res, 0, i_datistemplate);
2708 	datconnlimit = PQgetvalue(res, 0, i_datconnlimit);
2709 	tablespace = PQgetvalue(res, 0, i_tablespace);
2710 
2711 	qdatname = pg_strdup(fmtId(datname));
2712 
2713 	/*
2714 	 * Prepare the CREATE DATABASE command.  We must specify encoding, locale,
2715 	 * and tablespace since those can't be altered later.  Other DB properties
2716 	 * are left to the DATABASE PROPERTIES entry, so that they can be applied
2717 	 * after reconnecting to the target DB.
2718 	 */
2719 	appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
2720 					  qdatname);
2721 	if (strlen(encoding) > 0)
2722 	{
2723 		appendPQExpBufferStr(creaQry, " ENCODING = ");
2724 		appendStringLiteralAH(creaQry, encoding, fout);
2725 	}
2726 	if (strlen(collate) > 0)
2727 	{
2728 		appendPQExpBufferStr(creaQry, " LC_COLLATE = ");
2729 		appendStringLiteralAH(creaQry, collate, fout);
2730 	}
2731 	if (strlen(ctype) > 0)
2732 	{
2733 		appendPQExpBufferStr(creaQry, " LC_CTYPE = ");
2734 		appendStringLiteralAH(creaQry, ctype, fout);
2735 	}
2736 
2737 	/*
2738 	 * Note: looking at dopt->outputNoTablespaces here is completely the wrong
2739 	 * thing; the decision whether to specify a tablespace should be left till
2740 	 * pg_restore, so that pg_restore --no-tablespaces applies.  Ideally we'd
2741 	 * label the DATABASE entry with the tablespace and let the normal
2742 	 * tablespace selection logic work ... but CREATE DATABASE doesn't pay
2743 	 * attention to default_tablespace, so that won't work.
2744 	 */
2745 	if (strlen(tablespace) > 0 && strcmp(tablespace, "pg_default") != 0 &&
2746 		!dopt->outputNoTablespaces)
2747 		appendPQExpBuffer(creaQry, " TABLESPACE = %s",
2748 						  fmtId(tablespace));
2749 	appendPQExpBufferStr(creaQry, ";\n");
2750 
2751 	appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
2752 					  qdatname);
2753 
2754 	dbDumpId = createDumpId();
2755 
2756 	ArchiveEntry(fout,
2757 				 dbCatId,		/* catalog ID */
2758 				 dbDumpId,		/* dump ID */
2759 				 datname,		/* Name */
2760 				 NULL,			/* Namespace */
2761 				 NULL,			/* Tablespace */
2762 				 dba,			/* Owner */
2763 				 false,			/* with oids */
2764 				 "DATABASE",	/* Desc */
2765 				 SECTION_PRE_DATA,	/* Section */
2766 				 creaQry->data, /* Create */
2767 				 delQry->data,	/* Del */
2768 				 NULL,			/* Copy */
2769 				 NULL,			/* Deps */
2770 				 0,				/* # Deps */
2771 				 NULL,			/* Dumper */
2772 				 NULL);			/* Dumper Arg */
2773 
2774 	/* Compute correct tag for archive entry */
2775 	appendPQExpBuffer(labelq, "DATABASE %s", qdatname);
2776 
2777 	/* Dump DB comment if any */
2778 	if (fout->remoteVersion >= 80200)
2779 	{
2780 		/*
2781 		 * 8.2 and up keep comments on shared objects in a shared table, so we
2782 		 * cannot use the dumpComment() code used for other database objects.
2783 		 * Be careful that the ArchiveEntry parameters match that function.
2784 		 */
2785 		char	   *comment = PQgetvalue(res, 0, PQfnumber(res, "description"));
2786 
2787 		if (comment && *comment && !dopt->no_comments)
2788 		{
2789 			resetPQExpBuffer(dbQry);
2790 
2791 			/*
2792 			 * Generates warning when loaded into a differently-named
2793 			 * database.
2794 			 */
2795 			appendPQExpBuffer(dbQry, "COMMENT ON DATABASE %s IS ", qdatname);
2796 			appendStringLiteralAH(dbQry, comment, fout);
2797 			appendPQExpBufferStr(dbQry, ";\n");
2798 
2799 			ArchiveEntry(fout, nilCatalogId, createDumpId(),
2800 						 labelq->data, NULL, NULL, dba,
2801 						 false, "COMMENT", SECTION_NONE,
2802 						 dbQry->data, "", NULL,
2803 						 &(dbDumpId), 1,
2804 						 NULL, NULL);
2805 		}
2806 	}
2807 	else
2808 	{
2809 		dumpComment(fout, "DATABASE", qdatname, NULL, dba,
2810 					dbCatId, 0, dbDumpId);
2811 	}
2812 
2813 	/* Dump DB security label, if enabled */
2814 	if (!dopt->no_security_labels && fout->remoteVersion >= 90200)
2815 	{
2816 		PGresult   *shres;
2817 		PQExpBuffer seclabelQry;
2818 
2819 		seclabelQry = createPQExpBuffer();
2820 
2821 		buildShSecLabelQuery(conn, "pg_database", dbCatId.oid, seclabelQry);
2822 		shres = ExecuteSqlQuery(fout, seclabelQry->data, PGRES_TUPLES_OK);
2823 		resetPQExpBuffer(seclabelQry);
2824 		emitShSecLabels(conn, shres, seclabelQry, "DATABASE", datname);
2825 		if (seclabelQry->len > 0)
2826 			ArchiveEntry(fout, nilCatalogId, createDumpId(),
2827 						 labelq->data, NULL, NULL, dba,
2828 						 false, "SECURITY LABEL", SECTION_NONE,
2829 						 seclabelQry->data, "", NULL,
2830 						 &(dbDumpId), 1,
2831 						 NULL, NULL);
2832 		destroyPQExpBuffer(seclabelQry);
2833 		PQclear(shres);
2834 	}
2835 
2836 	/*
2837 	 * Dump ACL if any.  Note that we do not support initial privileges
2838 	 * (pg_init_privs) on databases.
2839 	 */
2840 	dumpACL(fout, dbDumpId, InvalidDumpId, "DATABASE",
2841 			qdatname, NULL, NULL,
2842 			dba, datacl, rdatacl, "", "");
2843 
2844 	/*
2845 	 * Now construct a DATABASE PROPERTIES archive entry to restore any
2846 	 * non-default database-level properties.  (The reason this must be
2847 	 * separate is that we cannot put any additional commands into the TOC
2848 	 * entry that has CREATE DATABASE.  pg_restore would execute such a group
2849 	 * in an implicit transaction block, and the backend won't allow CREATE
2850 	 * DATABASE in that context.)
2851 	 */
2852 	resetPQExpBuffer(creaQry);
2853 	resetPQExpBuffer(delQry);
2854 
2855 	if (strlen(datconnlimit) > 0 && strcmp(datconnlimit, "-1") != 0)
2856 		appendPQExpBuffer(creaQry, "ALTER DATABASE %s CONNECTION LIMIT = %s;\n",
2857 						  qdatname, datconnlimit);
2858 
2859 	if (strcmp(datistemplate, "t") == 0)
2860 	{
2861 		appendPQExpBuffer(creaQry, "ALTER DATABASE %s IS_TEMPLATE = true;\n",
2862 						  qdatname);
2863 
2864 		/*
2865 		 * The backend won't accept DROP DATABASE on a template database.  We
2866 		 * can deal with that by removing the template marking before the DROP
2867 		 * gets issued.  We'd prefer to use ALTER DATABASE IF EXISTS here, but
2868 		 * since no such command is currently supported, fake it with a direct
2869 		 * UPDATE on pg_database.
2870 		 */
2871 		appendPQExpBufferStr(delQry, "UPDATE pg_catalog.pg_database "
2872 							 "SET datistemplate = false WHERE datname = ");
2873 		appendStringLiteralAH(delQry, datname, fout);
2874 		appendPQExpBufferStr(delQry, ";\n");
2875 	}
2876 
2877 	/* Add database-specific SET options */
2878 	dumpDatabaseConfig(fout, creaQry, datname, dbCatId.oid);
2879 
2880 	/*
2881 	 * We stick this binary-upgrade query into the DATABASE PROPERTIES archive
2882 	 * entry, too, for lack of a better place.
2883 	 */
2884 	if (dopt->binary_upgrade)
2885 	{
2886 		appendPQExpBufferStr(creaQry, "\n-- For binary upgrade, set datfrozenxid and datminmxid.\n");
2887 		appendPQExpBuffer(creaQry, "UPDATE pg_catalog.pg_database\n"
2888 						  "SET datfrozenxid = '%u', datminmxid = '%u'\n"
2889 						  "WHERE datname = ",
2890 						  frozenxid, minmxid);
2891 		appendStringLiteralAH(creaQry, datname, fout);
2892 		appendPQExpBufferStr(creaQry, ";\n");
2893 	}
2894 
2895 	if (creaQry->len > 0)
2896 		ArchiveEntry(fout, nilCatalogId, createDumpId(),
2897 					 datname, NULL, NULL, dba,
2898 					 false, "DATABASE PROPERTIES", SECTION_PRE_DATA,
2899 					 creaQry->data, delQry->data, NULL,
2900 					 &(dbDumpId), 1,
2901 					 NULL, NULL);
2902 
2903 	/*
2904 	 * pg_largeobject and pg_largeobject_metadata come from the old system
2905 	 * intact, so set their relfrozenxids and relminmxids.
2906 	 */
2907 	if (dopt->binary_upgrade)
2908 	{
2909 		PGresult   *lo_res;
2910 		PQExpBuffer loFrozenQry = createPQExpBuffer();
2911 		PQExpBuffer loOutQry = createPQExpBuffer();
2912 		int			i_relfrozenxid,
2913 					i_relminmxid;
2914 
2915 		/*
2916 		 * pg_largeobject
2917 		 */
2918 		if (fout->remoteVersion >= 90300)
2919 			appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, relminmxid\n"
2920 							  "FROM pg_catalog.pg_class\n"
2921 							  "WHERE oid = %u;\n",
2922 							  LargeObjectRelationId);
2923 		else
2924 			appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, 0 AS relminmxid\n"
2925 							  "FROM pg_catalog.pg_class\n"
2926 							  "WHERE oid = %u;\n",
2927 							  LargeObjectRelationId);
2928 
2929 		lo_res = ExecuteSqlQueryForSingleRow(fout, loFrozenQry->data);
2930 
2931 		i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
2932 		i_relminmxid = PQfnumber(lo_res, "relminmxid");
2933 
2934 		appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, set pg_largeobject relfrozenxid and relminmxid\n");
2935 		appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
2936 						  "SET relfrozenxid = '%u', relminmxid = '%u'\n"
2937 						  "WHERE oid = %u;\n",
2938 						  atooid(PQgetvalue(lo_res, 0, i_relfrozenxid)),
2939 						  atooid(PQgetvalue(lo_res, 0, i_relminmxid)),
2940 						  LargeObjectRelationId);
2941 		ArchiveEntry(fout, nilCatalogId, createDumpId(),
2942 					 "pg_largeobject", NULL, NULL, "",
2943 					 false, "pg_largeobject", SECTION_PRE_DATA,
2944 					 loOutQry->data, "", NULL,
2945 					 NULL, 0,
2946 					 NULL, NULL);
2947 
2948 		PQclear(lo_res);
2949 
2950 		/*
2951 		 * pg_largeobject_metadata
2952 		 */
2953 		if (fout->remoteVersion >= 90000)
2954 		{
2955 			resetPQExpBuffer(loFrozenQry);
2956 			resetPQExpBuffer(loOutQry);
2957 
2958 			if (fout->remoteVersion >= 90300)
2959 				appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, relminmxid\n"
2960 								  "FROM pg_catalog.pg_class\n"
2961 								  "WHERE oid = %u;\n",
2962 								  LargeObjectMetadataRelationId);
2963 			else
2964 				appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid, 0 AS relminmxid\n"
2965 								  "FROM pg_catalog.pg_class\n"
2966 								  "WHERE oid = %u;\n",
2967 								  LargeObjectMetadataRelationId);
2968 
2969 			lo_res = ExecuteSqlQueryForSingleRow(fout, loFrozenQry->data);
2970 
2971 			i_relfrozenxid = PQfnumber(lo_res, "relfrozenxid");
2972 			i_relminmxid = PQfnumber(lo_res, "relminmxid");
2973 
2974 			appendPQExpBufferStr(loOutQry, "\n-- For binary upgrade, set pg_largeobject_metadata relfrozenxid and relminmxid\n");
2975 			appendPQExpBuffer(loOutQry, "UPDATE pg_catalog.pg_class\n"
2976 							  "SET relfrozenxid = '%u', relminmxid = '%u'\n"
2977 							  "WHERE oid = %u;\n",
2978 							  atooid(PQgetvalue(lo_res, 0, i_relfrozenxid)),
2979 							  atooid(PQgetvalue(lo_res, 0, i_relminmxid)),
2980 							  LargeObjectMetadataRelationId);
2981 			ArchiveEntry(fout, nilCatalogId, createDumpId(),
2982 						 "pg_largeobject_metadata", NULL, NULL, "",
2983 						 false, "pg_largeobject_metadata", SECTION_PRE_DATA,
2984 						 loOutQry->data, "", NULL,
2985 						 NULL, 0,
2986 						 NULL, NULL);
2987 
2988 			PQclear(lo_res);
2989 		}
2990 
2991 		destroyPQExpBuffer(loFrozenQry);
2992 		destroyPQExpBuffer(loOutQry);
2993 	}
2994 
2995 	PQclear(res);
2996 
2997 	free(qdatname);
2998 	destroyPQExpBuffer(dbQry);
2999 	destroyPQExpBuffer(delQry);
3000 	destroyPQExpBuffer(creaQry);
3001 	destroyPQExpBuffer(labelq);
3002 }
3003 
3004 /*
3005  * Collect any database-specific or role-and-database-specific SET options
3006  * for this database, and append them to outbuf.
3007  */
3008 static void
dumpDatabaseConfig(Archive * AH,PQExpBuffer outbuf,const char * dbname,Oid dboid)3009 dumpDatabaseConfig(Archive *AH, PQExpBuffer outbuf,
3010 				   const char *dbname, Oid dboid)
3011 {
3012 	PGconn	   *conn = GetConnection(AH);
3013 	PQExpBuffer buf = createPQExpBuffer();
3014 	PGresult   *res;
3015 	int			count = 1;
3016 
3017 	/*
3018 	 * First collect database-specific options.  Pre-8.4 server versions lack
3019 	 * unnest(), so we do this the hard way by querying once per subscript.
3020 	 */
3021 	for (;;)
3022 	{
3023 		if (AH->remoteVersion >= 90000)
3024 			printfPQExpBuffer(buf, "SELECT setconfig[%d] FROM pg_db_role_setting "
3025 							  "WHERE setrole = 0 AND setdatabase = '%u'::oid",
3026 							  count, dboid);
3027 		else
3028 			printfPQExpBuffer(buf, "SELECT datconfig[%d] FROM pg_database WHERE oid = '%u'::oid", count, dboid);
3029 
3030 		res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
3031 
3032 		if (PQntuples(res) == 1 &&
3033 			!PQgetisnull(res, 0, 0))
3034 		{
3035 			makeAlterConfigCommand(conn, PQgetvalue(res, 0, 0),
3036 								   "DATABASE", dbname, NULL, NULL,
3037 								   outbuf);
3038 			PQclear(res);
3039 			count++;
3040 		}
3041 		else
3042 		{
3043 			PQclear(res);
3044 			break;
3045 		}
3046 	}
3047 
3048 	/* Now look for role-and-database-specific options */
3049 	if (AH->remoteVersion >= 90000)
3050 	{
3051 		/* Here we can assume we have unnest() */
3052 		printfPQExpBuffer(buf, "SELECT rolname, unnest(setconfig) "
3053 						  "FROM pg_db_role_setting s, pg_roles r "
3054 						  "WHERE setrole = r.oid AND setdatabase = '%u'::oid",
3055 						  dboid);
3056 
3057 		res = ExecuteSqlQuery(AH, buf->data, PGRES_TUPLES_OK);
3058 
3059 		if (PQntuples(res) > 0)
3060 		{
3061 			int			i;
3062 
3063 			for (i = 0; i < PQntuples(res); i++)
3064 				makeAlterConfigCommand(conn, PQgetvalue(res, i, 1),
3065 									   "ROLE", PQgetvalue(res, i, 0),
3066 									   "DATABASE", dbname,
3067 									   outbuf);
3068 		}
3069 
3070 		PQclear(res);
3071 	}
3072 
3073 	destroyPQExpBuffer(buf);
3074 }
3075 
3076 /*
3077  * dumpEncoding: put the correct encoding into the archive
3078  */
3079 static void
dumpEncoding(Archive * AH)3080 dumpEncoding(Archive *AH)
3081 {
3082 	const char *encname = pg_encoding_to_char(AH->encoding);
3083 	PQExpBuffer qry = createPQExpBuffer();
3084 
3085 	if (g_verbose)
3086 		write_msg(NULL, "saving encoding = %s\n", encname);
3087 
3088 	appendPQExpBufferStr(qry, "SET client_encoding = ");
3089 	appendStringLiteralAH(qry, encname, AH);
3090 	appendPQExpBufferStr(qry, ";\n");
3091 
3092 	ArchiveEntry(AH, nilCatalogId, createDumpId(),
3093 				 "ENCODING", NULL, NULL, "",
3094 				 false, "ENCODING", SECTION_PRE_DATA,
3095 				 qry->data, "", NULL,
3096 				 NULL, 0,
3097 				 NULL, NULL);
3098 
3099 	destroyPQExpBuffer(qry);
3100 }
3101 
3102 
3103 /*
3104  * dumpStdStrings: put the correct escape string behavior into the archive
3105  */
3106 static void
dumpStdStrings(Archive * AH)3107 dumpStdStrings(Archive *AH)
3108 {
3109 	const char *stdstrings = AH->std_strings ? "on" : "off";
3110 	PQExpBuffer qry = createPQExpBuffer();
3111 
3112 	if (g_verbose)
3113 		write_msg(NULL, "saving standard_conforming_strings = %s\n",
3114 				  stdstrings);
3115 
3116 	appendPQExpBuffer(qry, "SET standard_conforming_strings = '%s';\n",
3117 					  stdstrings);
3118 
3119 	ArchiveEntry(AH, nilCatalogId, createDumpId(),
3120 				 "STDSTRINGS", NULL, NULL, "",
3121 				 false, "STDSTRINGS", SECTION_PRE_DATA,
3122 				 qry->data, "", NULL,
3123 				 NULL, 0,
3124 				 NULL, NULL);
3125 
3126 	destroyPQExpBuffer(qry);
3127 }
3128 
3129 /*
3130  * dumpSearchPath: record the active search_path in the archive
3131  */
3132 static void
dumpSearchPath(Archive * AH)3133 dumpSearchPath(Archive *AH)
3134 {
3135 	PQExpBuffer qry = createPQExpBuffer();
3136 	PQExpBuffer path = createPQExpBuffer();
3137 	PGresult   *res;
3138 	char	  **schemanames = NULL;
3139 	int			nschemanames = 0;
3140 	int			i;
3141 
3142 	/*
3143 	 * We use the result of current_schemas(), not the search_path GUC,
3144 	 * because that might contain wildcards such as "$user", which won't
3145 	 * necessarily have the same value during restore.  Also, this way avoids
3146 	 * listing schemas that may appear in search_path but not actually exist,
3147 	 * which seems like a prudent exclusion.
3148 	 */
3149 	res = ExecuteSqlQueryForSingleRow(AH,
3150 									  "SELECT pg_catalog.current_schemas(false)");
3151 
3152 	if (!parsePGArray(PQgetvalue(res, 0, 0), &schemanames, &nschemanames))
3153 		exit_horribly(NULL, "could not parse result of current_schemas()\n");
3154 
3155 	/*
3156 	 * We use set_config(), not a simple "SET search_path" command, because
3157 	 * the latter has less-clean behavior if the search path is empty.  While
3158 	 * that's likely to get fixed at some point, it seems like a good idea to
3159 	 * be as backwards-compatible as possible in what we put into archives.
3160 	 */
3161 	for (i = 0; i < nschemanames; i++)
3162 	{
3163 		if (i > 0)
3164 			appendPQExpBufferStr(path, ", ");
3165 		appendPQExpBufferStr(path, fmtId(schemanames[i]));
3166 	}
3167 
3168 	appendPQExpBufferStr(qry, "SELECT pg_catalog.set_config('search_path', ");
3169 	appendStringLiteralAH(qry, path->data, AH);
3170 	appendPQExpBufferStr(qry, ", false);\n");
3171 
3172 	if (g_verbose)
3173 		write_msg(NULL, "saving search_path = %s\n", path->data);
3174 
3175 	ArchiveEntry(AH, nilCatalogId, createDumpId(),
3176 				 "SEARCHPATH", NULL, NULL, "",
3177 				 false, "SEARCHPATH", SECTION_PRE_DATA,
3178 				 qry->data, "", NULL,
3179 				 NULL, 0,
3180 				 NULL, NULL);
3181 
3182 	/* Also save it in AH->searchpath, in case we're doing plain text dump */
3183 	AH->searchpath = pg_strdup(qry->data);
3184 
3185 	if (schemanames)
3186 		free(schemanames);
3187 	PQclear(res);
3188 	destroyPQExpBuffer(qry);
3189 	destroyPQExpBuffer(path);
3190 }
3191 
3192 
3193 /*
3194  * getBlobs:
3195  *	Collect schema-level data about large objects
3196  */
3197 static void
getBlobs(Archive * fout)3198 getBlobs(Archive *fout)
3199 {
3200 	DumpOptions *dopt = fout->dopt;
3201 	PQExpBuffer blobQry = createPQExpBuffer();
3202 	BlobInfo   *binfo;
3203 	DumpableObject *bdata;
3204 	PGresult   *res;
3205 	int			ntups;
3206 	int			i;
3207 	int			i_oid;
3208 	int			i_lomowner;
3209 	int			i_lomacl;
3210 	int			i_rlomacl;
3211 	int			i_initlomacl;
3212 	int			i_initrlomacl;
3213 
3214 	/* Verbose message */
3215 	if (g_verbose)
3216 		write_msg(NULL, "reading large objects\n");
3217 
3218 	/* Fetch BLOB OIDs, and owner/ACL data if >= 9.0 */
3219 	if (fout->remoteVersion >= 90600)
3220 	{
3221 		PQExpBuffer acl_subquery = createPQExpBuffer();
3222 		PQExpBuffer racl_subquery = createPQExpBuffer();
3223 		PQExpBuffer init_acl_subquery = createPQExpBuffer();
3224 		PQExpBuffer init_racl_subquery = createPQExpBuffer();
3225 
3226 		buildACLQueries(acl_subquery, racl_subquery, init_acl_subquery,
3227 						init_racl_subquery, "l.lomacl", "l.lomowner", "'L'",
3228 						dopt->binary_upgrade);
3229 
3230 		appendPQExpBuffer(blobQry,
3231 						  "SELECT l.oid, (%s l.lomowner) AS rolname, "
3232 						  "%s AS lomacl, "
3233 						  "%s AS rlomacl, "
3234 						  "%s AS initlomacl, "
3235 						  "%s AS initrlomacl "
3236 						  "FROM pg_largeobject_metadata l "
3237 						  "LEFT JOIN pg_init_privs pip ON "
3238 						  "(l.oid = pip.objoid "
3239 						  "AND pip.classoid = 'pg_largeobject'::regclass "
3240 						  "AND pip.objsubid = 0) ",
3241 						  username_subquery,
3242 						  acl_subquery->data,
3243 						  racl_subquery->data,
3244 						  init_acl_subquery->data,
3245 						  init_racl_subquery->data);
3246 
3247 		destroyPQExpBuffer(acl_subquery);
3248 		destroyPQExpBuffer(racl_subquery);
3249 		destroyPQExpBuffer(init_acl_subquery);
3250 		destroyPQExpBuffer(init_racl_subquery);
3251 	}
3252 	else if (fout->remoteVersion >= 90000)
3253 		appendPQExpBuffer(blobQry,
3254 						  "SELECT oid, (%s lomowner) AS rolname, lomacl, "
3255 						  "NULL AS rlomacl, NULL AS initlomacl, "
3256 						  "NULL AS initrlomacl "
3257 						  " FROM pg_largeobject_metadata",
3258 						  username_subquery);
3259 	else
3260 		appendPQExpBufferStr(blobQry,
3261 							 "SELECT DISTINCT loid AS oid, "
3262 							 "NULL::name AS rolname, NULL::oid AS lomacl, "
3263 							 "NULL::oid AS rlomacl, NULL::oid AS initlomacl, "
3264 							 "NULL::oid AS initrlomacl "
3265 							 " FROM pg_largeobject");
3266 
3267 	res = ExecuteSqlQuery(fout, blobQry->data, PGRES_TUPLES_OK);
3268 
3269 	i_oid = PQfnumber(res, "oid");
3270 	i_lomowner = PQfnumber(res, "rolname");
3271 	i_lomacl = PQfnumber(res, "lomacl");
3272 	i_rlomacl = PQfnumber(res, "rlomacl");
3273 	i_initlomacl = PQfnumber(res, "initlomacl");
3274 	i_initrlomacl = PQfnumber(res, "initrlomacl");
3275 
3276 	ntups = PQntuples(res);
3277 
3278 	/*
3279 	 * Each large object has its own BLOB archive entry.
3280 	 */
3281 	binfo = (BlobInfo *) pg_malloc(ntups * sizeof(BlobInfo));
3282 
3283 	for (i = 0; i < ntups; i++)
3284 	{
3285 		binfo[i].dobj.objType = DO_BLOB;
3286 		binfo[i].dobj.catId.tableoid = LargeObjectRelationId;
3287 		binfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3288 		AssignDumpId(&binfo[i].dobj);
3289 
3290 		binfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oid));
3291 		binfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_lomowner));
3292 		binfo[i].blobacl = pg_strdup(PQgetvalue(res, i, i_lomacl));
3293 		binfo[i].rblobacl = pg_strdup(PQgetvalue(res, i, i_rlomacl));
3294 		binfo[i].initblobacl = pg_strdup(PQgetvalue(res, i, i_initlomacl));
3295 		binfo[i].initrblobacl = pg_strdup(PQgetvalue(res, i, i_initrlomacl));
3296 
3297 		if (PQgetisnull(res, i, i_lomacl) &&
3298 			PQgetisnull(res, i, i_rlomacl) &&
3299 			PQgetisnull(res, i, i_initlomacl) &&
3300 			PQgetisnull(res, i, i_initrlomacl))
3301 			binfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
3302 
3303 		/*
3304 		 * In binary-upgrade mode for blobs, we do *not* dump out the data or
3305 		 * the ACLs, should any exist.  The data and ACL (if any) will be
3306 		 * copied by pg_upgrade, which simply copies the pg_largeobject and
3307 		 * pg_largeobject_metadata tables.
3308 		 *
3309 		 * We *do* dump out the definition of the blob because we need that to
3310 		 * make the restoration of the comments, and anything else, work since
3311 		 * pg_upgrade copies the files behind pg_largeobject and
3312 		 * pg_largeobject_metadata after the dump is restored.
3313 		 */
3314 		if (dopt->binary_upgrade)
3315 			binfo[i].dobj.dump &= ~(DUMP_COMPONENT_DATA | DUMP_COMPONENT_ACL);
3316 	}
3317 
3318 	/*
3319 	 * If we have any large objects, a "BLOBS" archive entry is needed. This
3320 	 * is just a placeholder for sorting; it carries no data now.
3321 	 */
3322 	if (ntups > 0)
3323 	{
3324 		bdata = (DumpableObject *) pg_malloc(sizeof(DumpableObject));
3325 		bdata->objType = DO_BLOB_DATA;
3326 		bdata->catId = nilCatalogId;
3327 		AssignDumpId(bdata);
3328 		bdata->name = pg_strdup("BLOBS");
3329 	}
3330 
3331 	PQclear(res);
3332 	destroyPQExpBuffer(blobQry);
3333 }
3334 
3335 /*
3336  * dumpBlob
3337  *
3338  * dump the definition (metadata) of the given large object
3339  */
3340 static void
dumpBlob(Archive * fout,BlobInfo * binfo)3341 dumpBlob(Archive *fout, BlobInfo *binfo)
3342 {
3343 	PQExpBuffer cquery = createPQExpBuffer();
3344 	PQExpBuffer dquery = createPQExpBuffer();
3345 
3346 	appendPQExpBuffer(cquery,
3347 					  "SELECT pg_catalog.lo_create('%s');\n",
3348 					  binfo->dobj.name);
3349 
3350 	appendPQExpBuffer(dquery,
3351 					  "SELECT pg_catalog.lo_unlink('%s');\n",
3352 					  binfo->dobj.name);
3353 
3354 	if (binfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
3355 		ArchiveEntry(fout, binfo->dobj.catId, binfo->dobj.dumpId,
3356 					 binfo->dobj.name,
3357 					 NULL, NULL,
3358 					 binfo->rolname, false,
3359 					 "BLOB", SECTION_PRE_DATA,
3360 					 cquery->data, dquery->data, NULL,
3361 					 NULL, 0,
3362 					 NULL, NULL);
3363 
3364 	/* Dump comment if any */
3365 	if (binfo->dobj.dump & DUMP_COMPONENT_COMMENT)
3366 		dumpComment(fout, "LARGE OBJECT", binfo->dobj.name,
3367 					NULL, binfo->rolname,
3368 					binfo->dobj.catId, 0, binfo->dobj.dumpId);
3369 
3370 	/* Dump security label if any */
3371 	if (binfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
3372 		dumpSecLabel(fout, "LARGE OBJECT", binfo->dobj.name,
3373 					 NULL, binfo->rolname,
3374 					 binfo->dobj.catId, 0, binfo->dobj.dumpId);
3375 
3376 	/* Dump ACL if any */
3377 	if (binfo->blobacl && (binfo->dobj.dump & DUMP_COMPONENT_ACL))
3378 		dumpACL(fout, binfo->dobj.dumpId, InvalidDumpId, "LARGE OBJECT",
3379 				binfo->dobj.name, NULL,
3380 				NULL, binfo->rolname, binfo->blobacl, binfo->rblobacl,
3381 				binfo->initblobacl, binfo->initrblobacl);
3382 
3383 	destroyPQExpBuffer(cquery);
3384 	destroyPQExpBuffer(dquery);
3385 }
3386 
3387 /*
3388  * dumpBlobs:
3389  *	dump the data contents of all large objects
3390  */
3391 static int
dumpBlobs(Archive * fout,void * arg)3392 dumpBlobs(Archive *fout, void *arg)
3393 {
3394 	const char *blobQry;
3395 	const char *blobFetchQry;
3396 	PGconn	   *conn = GetConnection(fout);
3397 	PGresult   *res;
3398 	char		buf[LOBBUFSIZE];
3399 	int			ntups;
3400 	int			i;
3401 	int			cnt;
3402 
3403 	if (g_verbose)
3404 		write_msg(NULL, "saving large objects\n");
3405 
3406 	/*
3407 	 * Currently, we re-fetch all BLOB OIDs using a cursor.  Consider scanning
3408 	 * the already-in-memory dumpable objects instead...
3409 	 */
3410 	if (fout->remoteVersion >= 90000)
3411 		blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_largeobject_metadata";
3412 	else
3413 		blobQry = "DECLARE bloboid CURSOR FOR SELECT DISTINCT loid FROM pg_largeobject";
3414 
3415 	ExecuteSqlStatement(fout, blobQry);
3416 
3417 	/* Command to fetch from cursor */
3418 	blobFetchQry = "FETCH 1000 IN bloboid";
3419 
3420 	do
3421 	{
3422 		/* Do a fetch */
3423 		res = ExecuteSqlQuery(fout, blobFetchQry, PGRES_TUPLES_OK);
3424 
3425 		/* Process the tuples, if any */
3426 		ntups = PQntuples(res);
3427 		for (i = 0; i < ntups; i++)
3428 		{
3429 			Oid			blobOid;
3430 			int			loFd;
3431 
3432 			blobOid = atooid(PQgetvalue(res, i, 0));
3433 			/* Open the BLOB */
3434 			loFd = lo_open(conn, blobOid, INV_READ);
3435 			if (loFd == -1)
3436 				exit_horribly(NULL, "could not open large object %u: %s",
3437 							  blobOid, PQerrorMessage(conn));
3438 
3439 			StartBlob(fout, blobOid);
3440 
3441 			/* Now read it in chunks, sending data to archive */
3442 			do
3443 			{
3444 				cnt = lo_read(conn, loFd, buf, LOBBUFSIZE);
3445 				if (cnt < 0)
3446 					exit_horribly(NULL, "error reading large object %u: %s",
3447 								  blobOid, PQerrorMessage(conn));
3448 
3449 				WriteData(fout, buf, cnt);
3450 			} while (cnt > 0);
3451 
3452 			lo_close(conn, loFd);
3453 
3454 			EndBlob(fout, blobOid);
3455 		}
3456 
3457 		PQclear(res);
3458 	} while (ntups > 0);
3459 
3460 	return 1;
3461 }
3462 
3463 /*
3464  * getPolicies
3465  *	  get information about all RLS policies on dumpable tables.
3466  */
3467 void
getPolicies(Archive * fout,TableInfo tblinfo[],int numTables)3468 getPolicies(Archive *fout, TableInfo tblinfo[], int numTables)
3469 {
3470 	PQExpBuffer query;
3471 	PGresult   *res;
3472 	PolicyInfo *polinfo;
3473 	int			i_oid;
3474 	int			i_tableoid;
3475 	int			i_polrelid;
3476 	int			i_polname;
3477 	int			i_polcmd;
3478 	int			i_polpermissive;
3479 	int			i_polroles;
3480 	int			i_polqual;
3481 	int			i_polwithcheck;
3482 	int			i,
3483 				j,
3484 				ntups;
3485 
3486 	if (fout->remoteVersion < 90500)
3487 		return;
3488 
3489 	query = createPQExpBuffer();
3490 
3491 	/*
3492 	 * First, check which tables have RLS enabled.  We represent RLS being
3493 	 * enabled on a table by creating a PolicyInfo object with null polname.
3494 	 */
3495 	for (i = 0; i < numTables; i++)
3496 	{
3497 		TableInfo  *tbinfo = &tblinfo[i];
3498 
3499 		/* Ignore row security on tables not to be dumped */
3500 		if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
3501 			continue;
3502 
3503 		if (tbinfo->rowsec)
3504 		{
3505 			/*
3506 			 * Note: use tableoid 0 so that this object won't be mistaken for
3507 			 * something that pg_depend entries apply to.
3508 			 */
3509 			polinfo = pg_malloc(sizeof(PolicyInfo));
3510 			polinfo->dobj.objType = DO_POLICY;
3511 			polinfo->dobj.catId.tableoid = 0;
3512 			polinfo->dobj.catId.oid = tbinfo->dobj.catId.oid;
3513 			AssignDumpId(&polinfo->dobj);
3514 			polinfo->dobj.namespace = tbinfo->dobj.namespace;
3515 			polinfo->dobj.name = pg_strdup(tbinfo->dobj.name);
3516 			polinfo->poltable = tbinfo;
3517 			polinfo->polname = NULL;
3518 			polinfo->polcmd = '\0';
3519 			polinfo->polpermissive = 0;
3520 			polinfo->polroles = NULL;
3521 			polinfo->polqual = NULL;
3522 			polinfo->polwithcheck = NULL;
3523 		}
3524 	}
3525 
3526 	/*
3527 	 * Now, read all RLS policies, and create PolicyInfo objects for all those
3528 	 * that are of interest.
3529 	 */
3530 	if (g_verbose)
3531 		write_msg(NULL, "reading row-level security policies\n");
3532 
3533 	printfPQExpBuffer(query,
3534 					  "SELECT oid, tableoid, pol.polrelid, pol.polname, pol.polcmd, ");
3535 	if (fout->remoteVersion >= 100000)
3536 		appendPQExpBuffer(query, "pol.polpermissive, ");
3537 	else
3538 		appendPQExpBuffer(query, "'t' as polpermissive, ");
3539 	appendPQExpBuffer(query,
3540 					  "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE "
3541 					  "   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, "
3542 					  "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
3543 					  "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
3544 					  "FROM pg_catalog.pg_policy pol");
3545 
3546 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3547 
3548 	ntups = PQntuples(res);
3549 	if (ntups > 0)
3550 	{
3551 		i_oid = PQfnumber(res, "oid");
3552 		i_tableoid = PQfnumber(res, "tableoid");
3553 		i_polrelid = PQfnumber(res, "polrelid");
3554 		i_polname = PQfnumber(res, "polname");
3555 		i_polcmd = PQfnumber(res, "polcmd");
3556 		i_polpermissive = PQfnumber(res, "polpermissive");
3557 		i_polroles = PQfnumber(res, "polroles");
3558 		i_polqual = PQfnumber(res, "polqual");
3559 		i_polwithcheck = PQfnumber(res, "polwithcheck");
3560 
3561 		polinfo = pg_malloc(ntups * sizeof(PolicyInfo));
3562 
3563 		for (j = 0; j < ntups; j++)
3564 		{
3565 			Oid			polrelid = atooid(PQgetvalue(res, j, i_polrelid));
3566 			TableInfo  *tbinfo = findTableByOid(polrelid);
3567 
3568 			/*
3569 			 * Ignore row security on tables not to be dumped.  (This will
3570 			 * result in some harmless wasted slots in polinfo[].)
3571 			 */
3572 			if (!(tbinfo->dobj.dump & DUMP_COMPONENT_POLICY))
3573 				continue;
3574 
3575 			polinfo[j].dobj.objType = DO_POLICY;
3576 			polinfo[j].dobj.catId.tableoid =
3577 				atooid(PQgetvalue(res, j, i_tableoid));
3578 			polinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
3579 			AssignDumpId(&polinfo[j].dobj);
3580 			polinfo[j].dobj.namespace = tbinfo->dobj.namespace;
3581 			polinfo[j].poltable = tbinfo;
3582 			polinfo[j].polname = pg_strdup(PQgetvalue(res, j, i_polname));
3583 			polinfo[j].dobj.name = pg_strdup(polinfo[j].polname);
3584 
3585 			polinfo[j].polcmd = *(PQgetvalue(res, j, i_polcmd));
3586 			polinfo[j].polpermissive = *(PQgetvalue(res, j, i_polpermissive)) == 't';
3587 
3588 			if (PQgetisnull(res, j, i_polroles))
3589 				polinfo[j].polroles = NULL;
3590 			else
3591 				polinfo[j].polroles = pg_strdup(PQgetvalue(res, j, i_polroles));
3592 
3593 			if (PQgetisnull(res, j, i_polqual))
3594 				polinfo[j].polqual = NULL;
3595 			else
3596 				polinfo[j].polqual = pg_strdup(PQgetvalue(res, j, i_polqual));
3597 
3598 			if (PQgetisnull(res, j, i_polwithcheck))
3599 				polinfo[j].polwithcheck = NULL;
3600 			else
3601 				polinfo[j].polwithcheck
3602 					= pg_strdup(PQgetvalue(res, j, i_polwithcheck));
3603 		}
3604 	}
3605 
3606 	PQclear(res);
3607 
3608 	destroyPQExpBuffer(query);
3609 }
3610 
3611 /*
3612  * dumpPolicy
3613  *	  dump the definition of the given policy
3614  */
3615 static void
dumpPolicy(Archive * fout,PolicyInfo * polinfo)3616 dumpPolicy(Archive *fout, PolicyInfo *polinfo)
3617 {
3618 	DumpOptions *dopt = fout->dopt;
3619 	TableInfo  *tbinfo = polinfo->poltable;
3620 	PQExpBuffer query;
3621 	PQExpBuffer delqry;
3622 	PQExpBuffer polprefix;
3623 	char	   *qtabname;
3624 	const char *cmd;
3625 	char	   *tag;
3626 
3627 	if (dopt->dataOnly)
3628 		return;
3629 
3630 	/*
3631 	 * If polname is NULL, then this record is just indicating that ROW LEVEL
3632 	 * SECURITY is enabled for the table. Dump as ALTER TABLE <table> ENABLE
3633 	 * ROW LEVEL SECURITY.
3634 	 */
3635 	if (polinfo->polname == NULL)
3636 	{
3637 		query = createPQExpBuffer();
3638 
3639 		appendPQExpBuffer(query, "ALTER TABLE %s ENABLE ROW LEVEL SECURITY;",
3640 						  fmtQualifiedDumpable(tbinfo));
3641 
3642 		/*
3643 		 * We must emit the ROW SECURITY object's dependency on its table
3644 		 * explicitly, because it will not match anything in pg_depend (unlike
3645 		 * the case for other PolicyInfo objects).
3646 		 */
3647 		if (polinfo->dobj.dump & DUMP_COMPONENT_POLICY)
3648 			ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
3649 						 polinfo->dobj.name,
3650 						 polinfo->dobj.namespace->dobj.name,
3651 						 NULL,
3652 						 tbinfo->rolname, false,
3653 						 "ROW SECURITY", SECTION_POST_DATA,
3654 						 query->data, "", NULL,
3655 						 &(tbinfo->dobj.dumpId), 1,
3656 						 NULL, NULL);
3657 
3658 		destroyPQExpBuffer(query);
3659 		return;
3660 	}
3661 
3662 	if (polinfo->polcmd == '*')
3663 		cmd = "";
3664 	else if (polinfo->polcmd == 'r')
3665 		cmd = " FOR SELECT";
3666 	else if (polinfo->polcmd == 'a')
3667 		cmd = " FOR INSERT";
3668 	else if (polinfo->polcmd == 'w')
3669 		cmd = " FOR UPDATE";
3670 	else if (polinfo->polcmd == 'd')
3671 		cmd = " FOR DELETE";
3672 	else
3673 	{
3674 		write_msg(NULL, "unexpected policy command type: %c\n",
3675 				  polinfo->polcmd);
3676 		exit_nicely(1);
3677 	}
3678 
3679 	query = createPQExpBuffer();
3680 	delqry = createPQExpBuffer();
3681 	polprefix = createPQExpBuffer();
3682 
3683 	qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
3684 
3685 	appendPQExpBuffer(query, "CREATE POLICY %s", fmtId(polinfo->polname));
3686 
3687 	appendPQExpBuffer(query, " ON %s%s%s", fmtQualifiedDumpable(tbinfo),
3688 					  !polinfo->polpermissive ? " AS RESTRICTIVE" : "", cmd);
3689 
3690 	if (polinfo->polroles != NULL)
3691 		appendPQExpBuffer(query, " TO %s", polinfo->polroles);
3692 
3693 	if (polinfo->polqual != NULL)
3694 		appendPQExpBuffer(query, " USING (%s)", polinfo->polqual);
3695 
3696 	if (polinfo->polwithcheck != NULL)
3697 		appendPQExpBuffer(query, " WITH CHECK (%s)", polinfo->polwithcheck);
3698 
3699 	appendPQExpBuffer(query, ";\n");
3700 
3701 	appendPQExpBuffer(delqry, "DROP POLICY %s", fmtId(polinfo->polname));
3702 	appendPQExpBuffer(delqry, " ON %s;\n", fmtQualifiedDumpable(tbinfo));
3703 
3704 	appendPQExpBuffer(polprefix, "POLICY %s ON",
3705 					  fmtId(polinfo->polname));
3706 
3707 	tag = psprintf("%s %s", tbinfo->dobj.name, polinfo->dobj.name);
3708 
3709 	if (polinfo->dobj.dump & DUMP_COMPONENT_POLICY)
3710 		ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
3711 					 tag,
3712 					 polinfo->dobj.namespace->dobj.name,
3713 					 NULL,
3714 					 tbinfo->rolname, false,
3715 					 "POLICY", SECTION_POST_DATA,
3716 					 query->data, delqry->data, NULL,
3717 					 NULL, 0,
3718 					 NULL, NULL);
3719 
3720 	if (polinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
3721 		dumpComment(fout, polprefix->data, qtabname,
3722 					tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
3723 					polinfo->dobj.catId, 0, polinfo->dobj.dumpId);
3724 
3725 	free(tag);
3726 	destroyPQExpBuffer(query);
3727 	destroyPQExpBuffer(delqry);
3728 	destroyPQExpBuffer(polprefix);
3729 	free(qtabname);
3730 }
3731 
3732 /*
3733  * getPublications
3734  *	  get information about publications
3735  */
3736 PublicationInfo *
getPublications(Archive * fout,int * numPublications)3737 getPublications(Archive *fout, int *numPublications)
3738 {
3739 	DumpOptions *dopt = fout->dopt;
3740 	PQExpBuffer query;
3741 	PGresult   *res;
3742 	PublicationInfo *pubinfo;
3743 	int			i_tableoid;
3744 	int			i_oid;
3745 	int			i_pubname;
3746 	int			i_rolname;
3747 	int			i_puballtables;
3748 	int			i_pubinsert;
3749 	int			i_pubupdate;
3750 	int			i_pubdelete;
3751 	int			i_pubtruncate;
3752 	int			i,
3753 				ntups;
3754 
3755 	if (dopt->no_publications || fout->remoteVersion < 100000)
3756 	{
3757 		*numPublications = 0;
3758 		return NULL;
3759 	}
3760 
3761 	query = createPQExpBuffer();
3762 
3763 	resetPQExpBuffer(query);
3764 
3765 	/* Get the publications. */
3766 	if (fout->remoteVersion >= 110000)
3767 		appendPQExpBuffer(query,
3768 						  "SELECT p.tableoid, p.oid, p.pubname, "
3769 						  "(%s p.pubowner) AS rolname, "
3770 						  "p.puballtables, p.pubinsert, p.pubupdate, p.pubdelete, p.pubtruncate "
3771 						  "FROM pg_publication p",
3772 						  username_subquery);
3773 	else
3774 		appendPQExpBuffer(query,
3775 						  "SELECT p.tableoid, p.oid, p.pubname, "
3776 						  "(%s p.pubowner) AS rolname, "
3777 						  "p.puballtables, p.pubinsert, p.pubupdate, p.pubdelete, false AS pubtruncate "
3778 						  "FROM pg_publication p",
3779 						  username_subquery);
3780 
3781 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3782 
3783 	ntups = PQntuples(res);
3784 
3785 	i_tableoid = PQfnumber(res, "tableoid");
3786 	i_oid = PQfnumber(res, "oid");
3787 	i_pubname = PQfnumber(res, "pubname");
3788 	i_rolname = PQfnumber(res, "rolname");
3789 	i_puballtables = PQfnumber(res, "puballtables");
3790 	i_pubinsert = PQfnumber(res, "pubinsert");
3791 	i_pubupdate = PQfnumber(res, "pubupdate");
3792 	i_pubdelete = PQfnumber(res, "pubdelete");
3793 	i_pubtruncate = PQfnumber(res, "pubtruncate");
3794 
3795 	pubinfo = pg_malloc(ntups * sizeof(PublicationInfo));
3796 
3797 	for (i = 0; i < ntups; i++)
3798 	{
3799 		pubinfo[i].dobj.objType = DO_PUBLICATION;
3800 		pubinfo[i].dobj.catId.tableoid =
3801 			atooid(PQgetvalue(res, i, i_tableoid));
3802 		pubinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3803 		AssignDumpId(&pubinfo[i].dobj);
3804 		pubinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_pubname));
3805 		pubinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
3806 		pubinfo[i].puballtables =
3807 			(strcmp(PQgetvalue(res, i, i_puballtables), "t") == 0);
3808 		pubinfo[i].pubinsert =
3809 			(strcmp(PQgetvalue(res, i, i_pubinsert), "t") == 0);
3810 		pubinfo[i].pubupdate =
3811 			(strcmp(PQgetvalue(res, i, i_pubupdate), "t") == 0);
3812 		pubinfo[i].pubdelete =
3813 			(strcmp(PQgetvalue(res, i, i_pubdelete), "t") == 0);
3814 		pubinfo[i].pubtruncate =
3815 			(strcmp(PQgetvalue(res, i, i_pubtruncate), "t") == 0);
3816 
3817 		if (strlen(pubinfo[i].rolname) == 0)
3818 			write_msg(NULL, "WARNING: owner of publication \"%s\" appears to be invalid\n",
3819 					  pubinfo[i].dobj.name);
3820 
3821 		/* Decide whether we want to dump it */
3822 		selectDumpableObject(&(pubinfo[i].dobj), fout);
3823 	}
3824 	PQclear(res);
3825 
3826 	destroyPQExpBuffer(query);
3827 
3828 	*numPublications = ntups;
3829 	return pubinfo;
3830 }
3831 
3832 /*
3833  * dumpPublication
3834  *	  dump the definition of the given publication
3835  */
3836 static void
dumpPublication(Archive * fout,PublicationInfo * pubinfo)3837 dumpPublication(Archive *fout, PublicationInfo *pubinfo)
3838 {
3839 	PQExpBuffer delq;
3840 	PQExpBuffer query;
3841 	char	   *qpubname;
3842 	bool		first = true;
3843 
3844 	if (!(pubinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
3845 		return;
3846 
3847 	delq = createPQExpBuffer();
3848 	query = createPQExpBuffer();
3849 
3850 	qpubname = pg_strdup(fmtId(pubinfo->dobj.name));
3851 
3852 	appendPQExpBuffer(delq, "DROP PUBLICATION %s;\n",
3853 					  qpubname);
3854 
3855 	appendPQExpBuffer(query, "CREATE PUBLICATION %s",
3856 					  qpubname);
3857 
3858 	if (pubinfo->puballtables)
3859 		appendPQExpBufferStr(query, " FOR ALL TABLES");
3860 
3861 	appendPQExpBufferStr(query, " WITH (publish = '");
3862 	if (pubinfo->pubinsert)
3863 	{
3864 		appendPQExpBufferStr(query, "insert");
3865 		first = false;
3866 	}
3867 
3868 	if (pubinfo->pubupdate)
3869 	{
3870 		if (!first)
3871 			appendPQExpBufferStr(query, ", ");
3872 
3873 		appendPQExpBufferStr(query, "update");
3874 		first = false;
3875 	}
3876 
3877 	if (pubinfo->pubdelete)
3878 	{
3879 		if (!first)
3880 			appendPQExpBufferStr(query, ", ");
3881 
3882 		appendPQExpBufferStr(query, "delete");
3883 		first = false;
3884 	}
3885 
3886 	if (pubinfo->pubtruncate)
3887 	{
3888 		if (!first)
3889 			appendPQExpBufferStr(query, ", ");
3890 
3891 		appendPQExpBufferStr(query, "truncate");
3892 		first = false;
3893 	}
3894 
3895 	appendPQExpBufferStr(query, "');\n");
3896 
3897 	ArchiveEntry(fout, pubinfo->dobj.catId, pubinfo->dobj.dumpId,
3898 				 pubinfo->dobj.name,
3899 				 NULL,
3900 				 NULL,
3901 				 pubinfo->rolname, false,
3902 				 "PUBLICATION", SECTION_POST_DATA,
3903 				 query->data, delq->data, NULL,
3904 				 NULL, 0,
3905 				 NULL, NULL);
3906 
3907 	if (pubinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
3908 		dumpComment(fout, "PUBLICATION", qpubname,
3909 					NULL, pubinfo->rolname,
3910 					pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
3911 
3912 	if (pubinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
3913 		dumpSecLabel(fout, "PUBLICATION", qpubname,
3914 					 NULL, pubinfo->rolname,
3915 					 pubinfo->dobj.catId, 0, pubinfo->dobj.dumpId);
3916 
3917 	destroyPQExpBuffer(delq);
3918 	destroyPQExpBuffer(query);
3919 	free(qpubname);
3920 }
3921 
3922 /*
3923  * getPublicationTables
3924  *	  get information about publication membership for dumpable tables.
3925  */
3926 void
getPublicationTables(Archive * fout,TableInfo tblinfo[],int numTables)3927 getPublicationTables(Archive *fout, TableInfo tblinfo[], int numTables)
3928 {
3929 	PQExpBuffer query;
3930 	PGresult   *res;
3931 	PublicationRelInfo *pubrinfo;
3932 	DumpOptions *dopt = fout->dopt;
3933 	int			i_tableoid;
3934 	int			i_oid;
3935 	int			i_prpubid;
3936 	int			i_prrelid;
3937 	int			i,
3938 				j,
3939 				ntups;
3940 
3941 	if (dopt->no_publications || fout->remoteVersion < 100000)
3942 		return;
3943 
3944 	query = createPQExpBuffer();
3945 
3946 	/* Collect all publication membership info. */
3947 	appendPQExpBufferStr(query,
3948 						 "SELECT tableoid, oid, prpubid, prrelid "
3949 						 "FROM pg_catalog.pg_publication_rel");
3950 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
3951 
3952 	ntups = PQntuples(res);
3953 
3954 	i_tableoid = PQfnumber(res, "tableoid");
3955 	i_oid = PQfnumber(res, "oid");
3956 	i_prpubid = PQfnumber(res, "prpubid");
3957 	i_prrelid = PQfnumber(res, "prrelid");
3958 
3959 	/* this allocation may be more than we need */
3960 	pubrinfo = pg_malloc(ntups * sizeof(PublicationRelInfo));
3961 	j = 0;
3962 
3963 	for (i = 0; i < ntups; i++)
3964 	{
3965 		Oid			prpubid = atooid(PQgetvalue(res, i, i_prpubid));
3966 		Oid			prrelid = atooid(PQgetvalue(res, i, i_prrelid));
3967 		PublicationInfo *pubinfo;
3968 		TableInfo  *tbinfo;
3969 
3970 		/*
3971 		 * Ignore any entries for which we aren't interested in either the
3972 		 * publication or the rel.
3973 		 */
3974 		pubinfo = findPublicationByOid(prpubid);
3975 		if (pubinfo == NULL)
3976 			continue;
3977 		tbinfo = findTableByOid(prrelid);
3978 		if (tbinfo == NULL)
3979 			continue;
3980 
3981 		/*
3982 		 * Ignore publication membership of tables whose definitions are not
3983 		 * to be dumped.
3984 		 */
3985 		if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
3986 			continue;
3987 
3988 		/* OK, make a DumpableObject for this relationship */
3989 		pubrinfo[j].dobj.objType = DO_PUBLICATION_REL;
3990 		pubrinfo[j].dobj.catId.tableoid =
3991 			atooid(PQgetvalue(res, i, i_tableoid));
3992 		pubrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
3993 		AssignDumpId(&pubrinfo[j].dobj);
3994 		pubrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
3995 		pubrinfo[j].dobj.name = tbinfo->dobj.name;
3996 		pubrinfo[j].publication = pubinfo;
3997 		pubrinfo[j].pubtable = tbinfo;
3998 
3999 		/* Decide whether we want to dump it */
4000 		selectDumpablePublicationTable(&(pubrinfo[j].dobj), fout);
4001 
4002 		j++;
4003 	}
4004 
4005 	PQclear(res);
4006 	destroyPQExpBuffer(query);
4007 }
4008 
4009 /*
4010  * dumpPublicationTable
4011  *	  dump the definition of the given publication table mapping
4012  */
4013 static void
dumpPublicationTable(Archive * fout,PublicationRelInfo * pubrinfo)4014 dumpPublicationTable(Archive *fout, PublicationRelInfo *pubrinfo)
4015 {
4016 	PublicationInfo *pubinfo = pubrinfo->publication;
4017 	TableInfo  *tbinfo = pubrinfo->pubtable;
4018 	PQExpBuffer query;
4019 	char	   *tag;
4020 
4021 	if (!(pubrinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
4022 		return;
4023 
4024 	tag = psprintf("%s %s", pubinfo->dobj.name, tbinfo->dobj.name);
4025 
4026 	query = createPQExpBuffer();
4027 
4028 	appendPQExpBuffer(query, "ALTER PUBLICATION %s ADD TABLE ONLY",
4029 					  fmtId(pubinfo->dobj.name));
4030 	appendPQExpBuffer(query, " %s;\n",
4031 					  fmtQualifiedDumpable(tbinfo));
4032 
4033 	/*
4034 	 * There is no point in creating a drop query as the drop is done by table
4035 	 * drop.  (If you think to change this, see also _printTocEntry().)
4036 	 * Although this object doesn't really have ownership as such, set the
4037 	 * owner field anyway to ensure that the command is run by the correct
4038 	 * role at restore time.
4039 	 */
4040 	ArchiveEntry(fout, pubrinfo->dobj.catId, pubrinfo->dobj.dumpId,
4041 				 tag,
4042 				 tbinfo->dobj.namespace->dobj.name,
4043 				 NULL,
4044 				 pubinfo->rolname, false,
4045 				 "PUBLICATION TABLE", SECTION_POST_DATA,
4046 				 query->data, "", NULL,
4047 				 NULL, 0,
4048 				 NULL, NULL);
4049 
4050 	free(tag);
4051 	destroyPQExpBuffer(query);
4052 }
4053 
4054 /*
4055  * Is the currently connected user a superuser?
4056  */
4057 static bool
is_superuser(Archive * fout)4058 is_superuser(Archive *fout)
4059 {
4060 	ArchiveHandle *AH = (ArchiveHandle *) fout;
4061 	const char *val;
4062 
4063 	val = PQparameterStatus(AH->connection, "is_superuser");
4064 
4065 	if (val && strcmp(val, "on") == 0)
4066 		return true;
4067 
4068 	return false;
4069 }
4070 
4071 /*
4072  * getSubscriptions
4073  *	  get information about subscriptions
4074  */
4075 void
getSubscriptions(Archive * fout)4076 getSubscriptions(Archive *fout)
4077 {
4078 	DumpOptions *dopt = fout->dopt;
4079 	PQExpBuffer query;
4080 	PGresult   *res;
4081 	SubscriptionInfo *subinfo;
4082 	int			i_tableoid;
4083 	int			i_oid;
4084 	int			i_subname;
4085 	int			i_rolname;
4086 	int			i_subconninfo;
4087 	int			i_subslotname;
4088 	int			i_subsynccommit;
4089 	int			i_subpublications;
4090 	int			i,
4091 				ntups;
4092 
4093 	if (dopt->no_subscriptions || fout->remoteVersion < 100000)
4094 		return;
4095 
4096 	if (!is_superuser(fout))
4097 	{
4098 		int			n;
4099 
4100 		res = ExecuteSqlQuery(fout,
4101 							  "SELECT count(*) FROM pg_subscription "
4102 							  "WHERE subdbid = (SELECT oid FROM pg_database"
4103 							  "                 WHERE datname = current_database())",
4104 							  PGRES_TUPLES_OK);
4105 		n = atoi(PQgetvalue(res, 0, 0));
4106 		if (n > 0)
4107 			write_msg(NULL, "WARNING: subscriptions not dumped because current user is not a superuser\n");
4108 		PQclear(res);
4109 		return;
4110 	}
4111 
4112 	query = createPQExpBuffer();
4113 
4114 	resetPQExpBuffer(query);
4115 
4116 	/* Get the subscriptions in current database. */
4117 	appendPQExpBuffer(query,
4118 					  "SELECT s.tableoid, s.oid, s.subname,"
4119 					  "(%s s.subowner) AS rolname, "
4120 					  " s.subconninfo, s.subslotname, s.subsynccommit, "
4121 					  " s.subpublications "
4122 					  "FROM pg_subscription s "
4123 					  "WHERE s.subdbid = (SELECT oid FROM pg_database"
4124 					  "                   WHERE datname = current_database())",
4125 					  username_subquery);
4126 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4127 
4128 	ntups = PQntuples(res);
4129 
4130 	i_tableoid = PQfnumber(res, "tableoid");
4131 	i_oid = PQfnumber(res, "oid");
4132 	i_subname = PQfnumber(res, "subname");
4133 	i_rolname = PQfnumber(res, "rolname");
4134 	i_subconninfo = PQfnumber(res, "subconninfo");
4135 	i_subslotname = PQfnumber(res, "subslotname");
4136 	i_subsynccommit = PQfnumber(res, "subsynccommit");
4137 	i_subpublications = PQfnumber(res, "subpublications");
4138 
4139 	subinfo = pg_malloc(ntups * sizeof(SubscriptionInfo));
4140 
4141 	for (i = 0; i < ntups; i++)
4142 	{
4143 		subinfo[i].dobj.objType = DO_SUBSCRIPTION;
4144 		subinfo[i].dobj.catId.tableoid =
4145 			atooid(PQgetvalue(res, i, i_tableoid));
4146 		subinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4147 		AssignDumpId(&subinfo[i].dobj);
4148 		subinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_subname));
4149 		subinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4150 		subinfo[i].subconninfo = pg_strdup(PQgetvalue(res, i, i_subconninfo));
4151 		if (PQgetisnull(res, i, i_subslotname))
4152 			subinfo[i].subslotname = NULL;
4153 		else
4154 			subinfo[i].subslotname = pg_strdup(PQgetvalue(res, i, i_subslotname));
4155 		subinfo[i].subsynccommit =
4156 			pg_strdup(PQgetvalue(res, i, i_subsynccommit));
4157 		subinfo[i].subpublications =
4158 			pg_strdup(PQgetvalue(res, i, i_subpublications));
4159 
4160 		if (strlen(subinfo[i].rolname) == 0)
4161 			write_msg(NULL, "WARNING: owner of subscription \"%s\" appears to be invalid\n",
4162 					  subinfo[i].dobj.name);
4163 
4164 		/* Decide whether we want to dump it */
4165 		selectDumpableObject(&(subinfo[i].dobj), fout);
4166 	}
4167 	PQclear(res);
4168 
4169 	destroyPQExpBuffer(query);
4170 }
4171 
4172 /*
4173  * dumpSubscription
4174  *	  dump the definition of the given subscription
4175  */
4176 static void
dumpSubscription(Archive * fout,SubscriptionInfo * subinfo)4177 dumpSubscription(Archive *fout, SubscriptionInfo *subinfo)
4178 {
4179 	PQExpBuffer delq;
4180 	PQExpBuffer query;
4181 	PQExpBuffer publications;
4182 	char	   *qsubname;
4183 	char	  **pubnames = NULL;
4184 	int			npubnames = 0;
4185 	int			i;
4186 
4187 	if (!(subinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
4188 		return;
4189 
4190 	delq = createPQExpBuffer();
4191 	query = createPQExpBuffer();
4192 
4193 	qsubname = pg_strdup(fmtId(subinfo->dobj.name));
4194 
4195 	appendPQExpBuffer(delq, "DROP SUBSCRIPTION %s;\n",
4196 					  qsubname);
4197 
4198 	appendPQExpBuffer(query, "CREATE SUBSCRIPTION %s CONNECTION ",
4199 					  qsubname);
4200 	appendStringLiteralAH(query, subinfo->subconninfo, fout);
4201 
4202 	/* Build list of quoted publications and append them to query. */
4203 	if (!parsePGArray(subinfo->subpublications, &pubnames, &npubnames))
4204 	{
4205 		write_msg(NULL,
4206 				  "WARNING: could not parse subpublications array\n");
4207 		if (pubnames)
4208 			free(pubnames);
4209 		pubnames = NULL;
4210 		npubnames = 0;
4211 	}
4212 
4213 	publications = createPQExpBuffer();
4214 	for (i = 0; i < npubnames; i++)
4215 	{
4216 		if (i > 0)
4217 			appendPQExpBufferStr(publications, ", ");
4218 
4219 		appendPQExpBufferStr(publications, fmtId(pubnames[i]));
4220 	}
4221 
4222 	appendPQExpBuffer(query, " PUBLICATION %s WITH (connect = false, slot_name = ", publications->data);
4223 	if (subinfo->subslotname)
4224 		appendStringLiteralAH(query, subinfo->subslotname, fout);
4225 	else
4226 		appendPQExpBufferStr(query, "NONE");
4227 
4228 	if (strcmp(subinfo->subsynccommit, "off") != 0)
4229 		appendPQExpBuffer(query, ", synchronous_commit = %s", fmtId(subinfo->subsynccommit));
4230 
4231 	appendPQExpBufferStr(query, ");\n");
4232 
4233 	ArchiveEntry(fout, subinfo->dobj.catId, subinfo->dobj.dumpId,
4234 				 subinfo->dobj.name,
4235 				 NULL,
4236 				 NULL,
4237 				 subinfo->rolname, false,
4238 				 "SUBSCRIPTION", SECTION_POST_DATA,
4239 				 query->data, delq->data, NULL,
4240 				 NULL, 0,
4241 				 NULL, NULL);
4242 
4243 	if (subinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
4244 		dumpComment(fout, "SUBSCRIPTION", qsubname,
4245 					NULL, subinfo->rolname,
4246 					subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
4247 
4248 	if (subinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
4249 		dumpSecLabel(fout, "SUBSCRIPTION", qsubname,
4250 					 NULL, subinfo->rolname,
4251 					 subinfo->dobj.catId, 0, subinfo->dobj.dumpId);
4252 
4253 	destroyPQExpBuffer(publications);
4254 	if (pubnames)
4255 		free(pubnames);
4256 
4257 	destroyPQExpBuffer(delq);
4258 	destroyPQExpBuffer(query);
4259 	free(qsubname);
4260 }
4261 
4262 /*
4263  * Given a "create query", append as many ALTER ... DEPENDS ON EXTENSION as
4264  * the object needs.
4265  */
4266 static void
append_depends_on_extension(Archive * fout,PQExpBuffer create,DumpableObject * dobj,const char * catalog,const char * keyword,const char * objname)4267 append_depends_on_extension(Archive *fout,
4268 							PQExpBuffer create,
4269 							DumpableObject *dobj,
4270 							const char *catalog,
4271 							const char *keyword,
4272 							const char *objname)
4273 {
4274 	if (dobj->depends_on_ext)
4275 	{
4276 		char   *nm;
4277 		PGresult   *res;
4278 		PQExpBuffer	query;
4279 		int		ntups;
4280 		int		i_extname;
4281 		int		i;
4282 
4283 		/* dodge fmtId() non-reentrancy */
4284 		nm = pg_strdup(objname);
4285 
4286 		query = createPQExpBuffer();
4287 		appendPQExpBuffer(query,
4288 						  "SELECT e.extname "
4289 						  "FROM pg_catalog.pg_depend d, pg_catalog.pg_extension e "
4290 						  "WHERE d.refobjid = e.oid AND classid = '%s'::pg_catalog.regclass "
4291 						  "AND objid = '%u'::pg_catalog.oid AND deptype = 'x' "
4292 						  "AND refclassid = 'pg_catalog.pg_extension'::pg_catalog.regclass",
4293 						  catalog,
4294 						  dobj->catId.oid);
4295 		res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4296 		ntups = PQntuples(res);
4297 		i_extname = PQfnumber(res, "extname");
4298 		for (i = 0; i < ntups; i++)
4299 		{
4300 			appendPQExpBuffer(create, "ALTER %s %s DEPENDS ON EXTENSION %s;\n",
4301 							  keyword, nm,
4302 							  fmtId(PQgetvalue(res, i, i_extname)));
4303 		}
4304 
4305 		PQclear(res);
4306 		destroyPQExpBuffer(query);
4307 		pg_free(nm);
4308 	}
4309 }
4310 
4311 
4312 static void
binary_upgrade_set_type_oids_by_type_oid(Archive * fout,PQExpBuffer upgrade_buffer,Oid pg_type_oid,bool force_array_type)4313 binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
4314 										 PQExpBuffer upgrade_buffer,
4315 										 Oid pg_type_oid,
4316 										 bool force_array_type)
4317 {
4318 	PQExpBuffer upgrade_query = createPQExpBuffer();
4319 	PGresult   *res;
4320 	Oid			pg_type_array_oid;
4321 
4322 	appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type oid\n");
4323 	appendPQExpBuffer(upgrade_buffer,
4324 					  "SELECT pg_catalog.binary_upgrade_set_next_pg_type_oid('%u'::pg_catalog.oid);\n\n",
4325 					  pg_type_oid);
4326 
4327 	/* we only support old >= 8.3 for binary upgrades */
4328 	appendPQExpBuffer(upgrade_query,
4329 					  "SELECT typarray "
4330 					  "FROM pg_catalog.pg_type "
4331 					  "WHERE oid = '%u'::pg_catalog.oid;",
4332 					  pg_type_oid);
4333 
4334 	res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
4335 
4336 	pg_type_array_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typarray")));
4337 
4338 	PQclear(res);
4339 
4340 	if (!OidIsValid(pg_type_array_oid) && force_array_type)
4341 	{
4342 		/*
4343 		 * If the old version didn't assign an array type, but the new version
4344 		 * does, we must select an unused type OID to assign.  This currently
4345 		 * only happens for domains, when upgrading pre-v11 to v11 and up.
4346 		 *
4347 		 * Note: local state here is kind of ugly, but we must have some,
4348 		 * since we mustn't choose the same unused OID more than once.
4349 		 */
4350 		static Oid	next_possible_free_oid = FirstNormalObjectId;
4351 		bool		is_dup;
4352 
4353 		do
4354 		{
4355 			++next_possible_free_oid;
4356 			printfPQExpBuffer(upgrade_query,
4357 							  "SELECT EXISTS(SELECT 1 "
4358 							  "FROM pg_catalog.pg_type "
4359 							  "WHERE oid = '%u'::pg_catalog.oid);",
4360 							  next_possible_free_oid);
4361 			res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
4362 			is_dup = (PQgetvalue(res, 0, 0)[0] == 't');
4363 			PQclear(res);
4364 		} while (is_dup);
4365 
4366 		pg_type_array_oid = next_possible_free_oid;
4367 	}
4368 
4369 	if (OidIsValid(pg_type_array_oid))
4370 	{
4371 		appendPQExpBufferStr(upgrade_buffer,
4372 							 "\n-- For binary upgrade, must preserve pg_type array oid\n");
4373 		appendPQExpBuffer(upgrade_buffer,
4374 						  "SELECT pg_catalog.binary_upgrade_set_next_array_pg_type_oid('%u'::pg_catalog.oid);\n\n",
4375 						  pg_type_array_oid);
4376 	}
4377 
4378 	destroyPQExpBuffer(upgrade_query);
4379 }
4380 
4381 static bool
binary_upgrade_set_type_oids_by_rel_oid(Archive * fout,PQExpBuffer upgrade_buffer,Oid pg_rel_oid)4382 binary_upgrade_set_type_oids_by_rel_oid(Archive *fout,
4383 										PQExpBuffer upgrade_buffer,
4384 										Oid pg_rel_oid)
4385 {
4386 	PQExpBuffer upgrade_query = createPQExpBuffer();
4387 	PGresult   *upgrade_res;
4388 	Oid			pg_type_oid;
4389 	bool		toast_set = false;
4390 
4391 	/* we only support old >= 8.3 for binary upgrades */
4392 	appendPQExpBuffer(upgrade_query,
4393 					  "SELECT c.reltype AS crel, t.reltype AS trel "
4394 					  "FROM pg_catalog.pg_class c "
4395 					  "LEFT JOIN pg_catalog.pg_class t ON "
4396 					  "  (c.reltoastrelid = t.oid) "
4397 					  "WHERE c.oid = '%u'::pg_catalog.oid;",
4398 					  pg_rel_oid);
4399 
4400 	upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
4401 
4402 	pg_type_oid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "crel")));
4403 
4404 	binary_upgrade_set_type_oids_by_type_oid(fout, upgrade_buffer,
4405 											 pg_type_oid, false);
4406 
4407 	if (!PQgetisnull(upgrade_res, 0, PQfnumber(upgrade_res, "trel")))
4408 	{
4409 		/* Toast tables do not have pg_type array rows */
4410 		Oid			pg_type_toast_oid = atooid(PQgetvalue(upgrade_res, 0,
4411 														  PQfnumber(upgrade_res, "trel")));
4412 
4413 		appendPQExpBufferStr(upgrade_buffer, "\n-- For binary upgrade, must preserve pg_type toast oid\n");
4414 		appendPQExpBuffer(upgrade_buffer,
4415 						  "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_type_oid('%u'::pg_catalog.oid);\n\n",
4416 						  pg_type_toast_oid);
4417 
4418 		toast_set = true;
4419 	}
4420 
4421 	PQclear(upgrade_res);
4422 	destroyPQExpBuffer(upgrade_query);
4423 
4424 	return toast_set;
4425 }
4426 
4427 static void
binary_upgrade_set_pg_class_oids(Archive * fout,PQExpBuffer upgrade_buffer,Oid pg_class_oid,bool is_index)4428 binary_upgrade_set_pg_class_oids(Archive *fout,
4429 								 PQExpBuffer upgrade_buffer, Oid pg_class_oid,
4430 								 bool is_index)
4431 {
4432 	PQExpBuffer upgrade_query = createPQExpBuffer();
4433 	PGresult   *upgrade_res;
4434 	Oid			pg_class_reltoastrelid;
4435 	Oid			pg_index_indexrelid;
4436 
4437 	appendPQExpBuffer(upgrade_query,
4438 					  "SELECT c.reltoastrelid, i.indexrelid "
4439 					  "FROM pg_catalog.pg_class c LEFT JOIN "
4440 					  "pg_catalog.pg_index i ON (c.reltoastrelid = i.indrelid AND i.indisvalid) "
4441 					  "WHERE c.oid = '%u'::pg_catalog.oid;",
4442 					  pg_class_oid);
4443 
4444 	upgrade_res = ExecuteSqlQueryForSingleRow(fout, upgrade_query->data);
4445 
4446 	pg_class_reltoastrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "reltoastrelid")));
4447 	pg_index_indexrelid = atooid(PQgetvalue(upgrade_res, 0, PQfnumber(upgrade_res, "indexrelid")));
4448 
4449 	appendPQExpBufferStr(upgrade_buffer,
4450 						 "\n-- For binary upgrade, must preserve pg_class oids\n");
4451 
4452 	if (!is_index)
4453 	{
4454 		appendPQExpBuffer(upgrade_buffer,
4455 						  "SELECT pg_catalog.binary_upgrade_set_next_heap_pg_class_oid('%u'::pg_catalog.oid);\n",
4456 						  pg_class_oid);
4457 		/* only tables have toast tables, not indexes */
4458 		if (OidIsValid(pg_class_reltoastrelid))
4459 		{
4460 			/*
4461 			 * One complexity is that the table definition might not require
4462 			 * the creation of a TOAST table, and the TOAST table might have
4463 			 * been created long after table creation, when the table was
4464 			 * loaded with wide data.  By setting the TOAST oid we force
4465 			 * creation of the TOAST heap and TOAST index by the backend so we
4466 			 * can cleanly copy the files during binary upgrade.
4467 			 */
4468 
4469 			appendPQExpBuffer(upgrade_buffer,
4470 							  "SELECT pg_catalog.binary_upgrade_set_next_toast_pg_class_oid('%u'::pg_catalog.oid);\n",
4471 							  pg_class_reltoastrelid);
4472 
4473 			/* every toast table has an index */
4474 			appendPQExpBuffer(upgrade_buffer,
4475 							  "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
4476 							  pg_index_indexrelid);
4477 		}
4478 	}
4479 	else
4480 		appendPQExpBuffer(upgrade_buffer,
4481 						  "SELECT pg_catalog.binary_upgrade_set_next_index_pg_class_oid('%u'::pg_catalog.oid);\n",
4482 						  pg_class_oid);
4483 
4484 	appendPQExpBufferChar(upgrade_buffer, '\n');
4485 
4486 	PQclear(upgrade_res);
4487 	destroyPQExpBuffer(upgrade_query);
4488 }
4489 
4490 /*
4491  * If the DumpableObject is a member of an extension, add a suitable
4492  * ALTER EXTENSION ADD command to the creation commands in upgrade_buffer.
4493  *
4494  * For somewhat historical reasons, objname should already be quoted,
4495  * but not objnamespace (if any).
4496  */
4497 static void
binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,DumpableObject * dobj,const char * objtype,const char * objname,const char * objnamespace)4498 binary_upgrade_extension_member(PQExpBuffer upgrade_buffer,
4499 								DumpableObject *dobj,
4500 								const char *objtype,
4501 								const char *objname,
4502 								const char *objnamespace)
4503 {
4504 	DumpableObject *extobj = NULL;
4505 	int			i;
4506 
4507 	if (!dobj->ext_member)
4508 		return;
4509 
4510 	/*
4511 	 * Find the parent extension.  We could avoid this search if we wanted to
4512 	 * add a link field to DumpableObject, but the space costs of that would
4513 	 * be considerable.  We assume that member objects could only have a
4514 	 * direct dependency on their own extension, not any others.
4515 	 */
4516 	for (i = 0; i < dobj->nDeps; i++)
4517 	{
4518 		extobj = findObjectByDumpId(dobj->dependencies[i]);
4519 		if (extobj && extobj->objType == DO_EXTENSION)
4520 			break;
4521 		extobj = NULL;
4522 	}
4523 	if (extobj == NULL)
4524 		exit_horribly(NULL, "could not find parent extension for %s %s\n",
4525 					  objtype, objname);
4526 
4527 	appendPQExpBufferStr(upgrade_buffer,
4528 						 "\n-- For binary upgrade, handle extension membership the hard way\n");
4529 	appendPQExpBuffer(upgrade_buffer, "ALTER EXTENSION %s ADD %s ",
4530 					  fmtId(extobj->name),
4531 					  objtype);
4532 	if (objnamespace && *objnamespace)
4533 		appendPQExpBuffer(upgrade_buffer, "%s.", fmtId(objnamespace));
4534 	appendPQExpBuffer(upgrade_buffer, "%s;\n", objname);
4535 }
4536 
4537 /*
4538  * getNamespaces:
4539  *	  read all namespaces in the system catalogs and return them in the
4540  * NamespaceInfo* structure
4541  *
4542  *	numNamespaces is set to the number of namespaces read in
4543  */
4544 NamespaceInfo *
getNamespaces(Archive * fout,int * numNamespaces)4545 getNamespaces(Archive *fout, int *numNamespaces)
4546 {
4547 	DumpOptions *dopt = fout->dopt;
4548 	PGresult   *res;
4549 	int			ntups;
4550 	int			i;
4551 	PQExpBuffer query;
4552 	NamespaceInfo *nsinfo;
4553 	int			i_tableoid;
4554 	int			i_oid;
4555 	int			i_nspname;
4556 	int			i_rolname;
4557 	int			i_nspacl;
4558 	int			i_rnspacl;
4559 	int			i_initnspacl;
4560 	int			i_initrnspacl;
4561 
4562 	query = createPQExpBuffer();
4563 
4564 	/*
4565 	 * we fetch all namespaces including system ones, so that every object we
4566 	 * read in can be linked to a containing namespace.
4567 	 */
4568 	if (fout->remoteVersion >= 90600)
4569 	{
4570 		PQExpBuffer acl_subquery = createPQExpBuffer();
4571 		PQExpBuffer racl_subquery = createPQExpBuffer();
4572 		PQExpBuffer init_acl_subquery = createPQExpBuffer();
4573 		PQExpBuffer init_racl_subquery = createPQExpBuffer();
4574 
4575 		buildACLQueries(acl_subquery, racl_subquery, init_acl_subquery,
4576 						init_racl_subquery, "n.nspacl", "n.nspowner", "'n'",
4577 						dopt->binary_upgrade);
4578 
4579 		appendPQExpBuffer(query, "SELECT n.tableoid, n.oid, n.nspname, "
4580 						  "(%s nspowner) AS rolname, "
4581 						  "%s as nspacl, "
4582 						  "%s as rnspacl, "
4583 						  "%s as initnspacl, "
4584 						  "%s as initrnspacl "
4585 						  "FROM pg_namespace n "
4586 						  "LEFT JOIN pg_init_privs pip "
4587 						  "ON (n.oid = pip.objoid "
4588 						  "AND pip.classoid = 'pg_namespace'::regclass "
4589 						  "AND pip.objsubid = 0",
4590 						  username_subquery,
4591 						  acl_subquery->data,
4592 						  racl_subquery->data,
4593 						  init_acl_subquery->data,
4594 						  init_racl_subquery->data);
4595 
4596 		appendPQExpBuffer(query, ") ");
4597 
4598 		destroyPQExpBuffer(acl_subquery);
4599 		destroyPQExpBuffer(racl_subquery);
4600 		destroyPQExpBuffer(init_acl_subquery);
4601 		destroyPQExpBuffer(init_racl_subquery);
4602 	}
4603 	else
4604 		appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
4605 						  "(%s nspowner) AS rolname, "
4606 						  "nspacl, NULL as rnspacl, "
4607 						  "NULL AS initnspacl, NULL as initrnspacl "
4608 						  "FROM pg_namespace",
4609 						  username_subquery);
4610 
4611 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4612 
4613 	ntups = PQntuples(res);
4614 
4615 	nsinfo = (NamespaceInfo *) pg_malloc(ntups * sizeof(NamespaceInfo));
4616 
4617 	i_tableoid = PQfnumber(res, "tableoid");
4618 	i_oid = PQfnumber(res, "oid");
4619 	i_nspname = PQfnumber(res, "nspname");
4620 	i_rolname = PQfnumber(res, "rolname");
4621 	i_nspacl = PQfnumber(res, "nspacl");
4622 	i_rnspacl = PQfnumber(res, "rnspacl");
4623 	i_initnspacl = PQfnumber(res, "initnspacl");
4624 	i_initrnspacl = PQfnumber(res, "initrnspacl");
4625 
4626 	for (i = 0; i < ntups; i++)
4627 	{
4628 		nsinfo[i].dobj.objType = DO_NAMESPACE;
4629 		nsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4630 		nsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4631 		AssignDumpId(&nsinfo[i].dobj);
4632 		nsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_nspname));
4633 		nsinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4634 		nsinfo[i].nspacl = pg_strdup(PQgetvalue(res, i, i_nspacl));
4635 		nsinfo[i].rnspacl = pg_strdup(PQgetvalue(res, i, i_rnspacl));
4636 		nsinfo[i].initnspacl = pg_strdup(PQgetvalue(res, i, i_initnspacl));
4637 		nsinfo[i].initrnspacl = pg_strdup(PQgetvalue(res, i, i_initrnspacl));
4638 
4639 		/* Decide whether to dump this namespace */
4640 		selectDumpableNamespace(&nsinfo[i], fout);
4641 
4642 		/*
4643 		 * Do not try to dump ACL if the ACL is empty or the default.
4644 		 *
4645 		 * This is useful because, for some schemas/objects, the only
4646 		 * component we are going to try and dump is the ACL and if we can
4647 		 * remove that then 'dump' goes to zero/false and we don't consider
4648 		 * this object for dumping at all later on.
4649 		 */
4650 		if (PQgetisnull(res, i, i_nspacl) && PQgetisnull(res, i, i_rnspacl) &&
4651 			PQgetisnull(res, i, i_initnspacl) &&
4652 			PQgetisnull(res, i, i_initrnspacl))
4653 			nsinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
4654 
4655 		if (strlen(nsinfo[i].rolname) == 0)
4656 			write_msg(NULL, "WARNING: owner of schema \"%s\" appears to be invalid\n",
4657 					  nsinfo[i].dobj.name);
4658 	}
4659 
4660 	PQclear(res);
4661 	destroyPQExpBuffer(query);
4662 
4663 	*numNamespaces = ntups;
4664 
4665 	return nsinfo;
4666 }
4667 
4668 /*
4669  * findNamespace:
4670  *		given a namespace OID, look up the info read by getNamespaces
4671  */
4672 static NamespaceInfo *
findNamespace(Archive * fout,Oid nsoid)4673 findNamespace(Archive *fout, Oid nsoid)
4674 {
4675 	NamespaceInfo *nsinfo;
4676 
4677 	nsinfo = findNamespaceByOid(nsoid);
4678 	if (nsinfo == NULL)
4679 		exit_horribly(NULL, "schema with OID %u does not exist\n", nsoid);
4680 	return nsinfo;
4681 }
4682 
4683 /*
4684  * getExtensions:
4685  *	  read all extensions in the system catalogs and return them in the
4686  * ExtensionInfo* structure
4687  *
4688  *	numExtensions is set to the number of extensions read in
4689  */
4690 ExtensionInfo *
getExtensions(Archive * fout,int * numExtensions)4691 getExtensions(Archive *fout, int *numExtensions)
4692 {
4693 	DumpOptions *dopt = fout->dopt;
4694 	PGresult   *res;
4695 	int			ntups;
4696 	int			i;
4697 	PQExpBuffer query;
4698 	ExtensionInfo *extinfo;
4699 	int			i_tableoid;
4700 	int			i_oid;
4701 	int			i_extname;
4702 	int			i_nspname;
4703 	int			i_extrelocatable;
4704 	int			i_extversion;
4705 	int			i_extconfig;
4706 	int			i_extcondition;
4707 
4708 	/*
4709 	 * Before 9.1, there are no extensions.
4710 	 */
4711 	if (fout->remoteVersion < 90100)
4712 	{
4713 		*numExtensions = 0;
4714 		return NULL;
4715 	}
4716 
4717 	query = createPQExpBuffer();
4718 
4719 	appendPQExpBufferStr(query, "SELECT x.tableoid, x.oid, "
4720 						 "x.extname, n.nspname, x.extrelocatable, x.extversion, x.extconfig, x.extcondition "
4721 						 "FROM pg_extension x "
4722 						 "JOIN pg_namespace n ON n.oid = x.extnamespace");
4723 
4724 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4725 
4726 	ntups = PQntuples(res);
4727 
4728 	extinfo = (ExtensionInfo *) pg_malloc(ntups * sizeof(ExtensionInfo));
4729 
4730 	i_tableoid = PQfnumber(res, "tableoid");
4731 	i_oid = PQfnumber(res, "oid");
4732 	i_extname = PQfnumber(res, "extname");
4733 	i_nspname = PQfnumber(res, "nspname");
4734 	i_extrelocatable = PQfnumber(res, "extrelocatable");
4735 	i_extversion = PQfnumber(res, "extversion");
4736 	i_extconfig = PQfnumber(res, "extconfig");
4737 	i_extcondition = PQfnumber(res, "extcondition");
4738 
4739 	for (i = 0; i < ntups; i++)
4740 	{
4741 		extinfo[i].dobj.objType = DO_EXTENSION;
4742 		extinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4743 		extinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4744 		AssignDumpId(&extinfo[i].dobj);
4745 		extinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_extname));
4746 		extinfo[i].namespace = pg_strdup(PQgetvalue(res, i, i_nspname));
4747 		extinfo[i].relocatable = *(PQgetvalue(res, i, i_extrelocatable)) == 't';
4748 		extinfo[i].extversion = pg_strdup(PQgetvalue(res, i, i_extversion));
4749 		extinfo[i].extconfig = pg_strdup(PQgetvalue(res, i, i_extconfig));
4750 		extinfo[i].extcondition = pg_strdup(PQgetvalue(res, i, i_extcondition));
4751 
4752 		/* Decide whether we want to dump it */
4753 		selectDumpableExtension(&(extinfo[i]), dopt);
4754 	}
4755 
4756 	PQclear(res);
4757 	destroyPQExpBuffer(query);
4758 
4759 	*numExtensions = ntups;
4760 
4761 	return extinfo;
4762 }
4763 
4764 /*
4765  * getTypes:
4766  *	  read all types in the system catalogs and return them in the
4767  * TypeInfo* structure
4768  *
4769  *	numTypes is set to the number of types read in
4770  *
4771  * NB: this must run after getFuncs() because we assume we can do
4772  * findFuncByOid().
4773  */
4774 TypeInfo *
getTypes(Archive * fout,int * numTypes)4775 getTypes(Archive *fout, int *numTypes)
4776 {
4777 	DumpOptions *dopt = fout->dopt;
4778 	PGresult   *res;
4779 	int			ntups;
4780 	int			i;
4781 	PQExpBuffer query = createPQExpBuffer();
4782 	TypeInfo   *tyinfo;
4783 	ShellTypeInfo *stinfo;
4784 	int			i_tableoid;
4785 	int			i_oid;
4786 	int			i_typname;
4787 	int			i_typnamespace;
4788 	int			i_typacl;
4789 	int			i_rtypacl;
4790 	int			i_inittypacl;
4791 	int			i_initrtypacl;
4792 	int			i_rolname;
4793 	int			i_typelem;
4794 	int			i_typrelid;
4795 	int			i_typrelkind;
4796 	int			i_typtype;
4797 	int			i_typisdefined;
4798 	int			i_isarray;
4799 
4800 	/*
4801 	 * we include even the built-in types because those may be used as array
4802 	 * elements by user-defined types
4803 	 *
4804 	 * we filter out the built-in types when we dump out the types
4805 	 *
4806 	 * same approach for undefined (shell) types and array types
4807 	 *
4808 	 * Note: as of 8.3 we can reliably detect whether a type is an
4809 	 * auto-generated array type by checking the element type's typarray.
4810 	 * (Before that the test is capable of generating false positives.) We
4811 	 * still check for name beginning with '_', though, so as to avoid the
4812 	 * cost of the subselect probe for all standard types.  This would have to
4813 	 * be revisited if the backend ever allows renaming of array types.
4814 	 */
4815 
4816 	if (fout->remoteVersion >= 90600)
4817 	{
4818 		PQExpBuffer acl_subquery = createPQExpBuffer();
4819 		PQExpBuffer racl_subquery = createPQExpBuffer();
4820 		PQExpBuffer initacl_subquery = createPQExpBuffer();
4821 		PQExpBuffer initracl_subquery = createPQExpBuffer();
4822 
4823 		buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
4824 						initracl_subquery, "t.typacl", "t.typowner", "'T'",
4825 						dopt->binary_upgrade);
4826 
4827 		appendPQExpBuffer(query, "SELECT t.tableoid, t.oid, t.typname, "
4828 						  "t.typnamespace, "
4829 						  "%s AS typacl, "
4830 						  "%s AS rtypacl, "
4831 						  "%s AS inittypacl, "
4832 						  "%s AS initrtypacl, "
4833 						  "(%s t.typowner) AS rolname, "
4834 						  "t.typelem, t.typrelid, "
4835 						  "CASE WHEN t.typrelid = 0 THEN ' '::\"char\" "
4836 						  "ELSE (SELECT relkind FROM pg_class WHERE oid = t.typrelid) END AS typrelkind, "
4837 						  "t.typtype, t.typisdefined, "
4838 						  "t.typname[0] = '_' AND t.typelem != 0 AND "
4839 						  "(SELECT typarray FROM pg_type te WHERE oid = t.typelem) = t.oid AS isarray "
4840 						  "FROM pg_type t "
4841 						  "LEFT JOIN pg_init_privs pip ON "
4842 						  "(t.oid = pip.objoid "
4843 						  "AND pip.classoid = 'pg_type'::regclass "
4844 						  "AND pip.objsubid = 0) ",
4845 						  acl_subquery->data,
4846 						  racl_subquery->data,
4847 						  initacl_subquery->data,
4848 						  initracl_subquery->data,
4849 						  username_subquery);
4850 
4851 		destroyPQExpBuffer(acl_subquery);
4852 		destroyPQExpBuffer(racl_subquery);
4853 		destroyPQExpBuffer(initacl_subquery);
4854 		destroyPQExpBuffer(initracl_subquery);
4855 	}
4856 	else if (fout->remoteVersion >= 90200)
4857 	{
4858 		appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
4859 						  "typnamespace, typacl, NULL as rtypacl, "
4860 						  "NULL AS inittypacl, NULL AS initrtypacl, "
4861 						  "(%s typowner) AS rolname, "
4862 						  "typelem, typrelid, "
4863 						  "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
4864 						  "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
4865 						  "typtype, typisdefined, "
4866 						  "typname[0] = '_' AND typelem != 0 AND "
4867 						  "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
4868 						  "FROM pg_type",
4869 						  username_subquery);
4870 	}
4871 	else if (fout->remoteVersion >= 80300)
4872 	{
4873 		appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
4874 						  "typnamespace, NULL AS typacl, NULL as rtypacl, "
4875 						  "NULL AS inittypacl, NULL AS initrtypacl, "
4876 						  "(%s typowner) AS rolname, "
4877 						  "typelem, typrelid, "
4878 						  "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
4879 						  "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
4880 						  "typtype, typisdefined, "
4881 						  "typname[0] = '_' AND typelem != 0 AND "
4882 						  "(SELECT typarray FROM pg_type te WHERE oid = pg_type.typelem) = oid AS isarray "
4883 						  "FROM pg_type",
4884 						  username_subquery);
4885 	}
4886 	else
4887 	{
4888 		appendPQExpBuffer(query, "SELECT tableoid, oid, typname, "
4889 						  "typnamespace, NULL AS typacl, NULL as rtypacl, "
4890 						  "NULL AS inittypacl, NULL AS initrtypacl, "
4891 						  "(%s typowner) AS rolname, "
4892 						  "typelem, typrelid, "
4893 						  "CASE WHEN typrelid = 0 THEN ' '::\"char\" "
4894 						  "ELSE (SELECT relkind FROM pg_class WHERE oid = typrelid) END AS typrelkind, "
4895 						  "typtype, typisdefined, "
4896 						  "typname[0] = '_' AND typelem != 0 AS isarray "
4897 						  "FROM pg_type",
4898 						  username_subquery);
4899 	}
4900 
4901 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
4902 
4903 	ntups = PQntuples(res);
4904 
4905 	tyinfo = (TypeInfo *) pg_malloc(ntups * sizeof(TypeInfo));
4906 
4907 	i_tableoid = PQfnumber(res, "tableoid");
4908 	i_oid = PQfnumber(res, "oid");
4909 	i_typname = PQfnumber(res, "typname");
4910 	i_typnamespace = PQfnumber(res, "typnamespace");
4911 	i_typacl = PQfnumber(res, "typacl");
4912 	i_rtypacl = PQfnumber(res, "rtypacl");
4913 	i_inittypacl = PQfnumber(res, "inittypacl");
4914 	i_initrtypacl = PQfnumber(res, "initrtypacl");
4915 	i_rolname = PQfnumber(res, "rolname");
4916 	i_typelem = PQfnumber(res, "typelem");
4917 	i_typrelid = PQfnumber(res, "typrelid");
4918 	i_typrelkind = PQfnumber(res, "typrelkind");
4919 	i_typtype = PQfnumber(res, "typtype");
4920 	i_typisdefined = PQfnumber(res, "typisdefined");
4921 	i_isarray = PQfnumber(res, "isarray");
4922 
4923 	for (i = 0; i < ntups; i++)
4924 	{
4925 		tyinfo[i].dobj.objType = DO_TYPE;
4926 		tyinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
4927 		tyinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
4928 		AssignDumpId(&tyinfo[i].dobj);
4929 		tyinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_typname));
4930 		tyinfo[i].dobj.namespace =
4931 			findNamespace(fout,
4932 						  atooid(PQgetvalue(res, i, i_typnamespace)));
4933 		tyinfo[i].ftypname = NULL;	/* may get filled later */
4934 		tyinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
4935 		tyinfo[i].typacl = pg_strdup(PQgetvalue(res, i, i_typacl));
4936 		tyinfo[i].rtypacl = pg_strdup(PQgetvalue(res, i, i_rtypacl));
4937 		tyinfo[i].inittypacl = pg_strdup(PQgetvalue(res, i, i_inittypacl));
4938 		tyinfo[i].initrtypacl = pg_strdup(PQgetvalue(res, i, i_initrtypacl));
4939 		tyinfo[i].typelem = atooid(PQgetvalue(res, i, i_typelem));
4940 		tyinfo[i].typrelid = atooid(PQgetvalue(res, i, i_typrelid));
4941 		tyinfo[i].typrelkind = *PQgetvalue(res, i, i_typrelkind);
4942 		tyinfo[i].typtype = *PQgetvalue(res, i, i_typtype);
4943 		tyinfo[i].shellType = NULL;
4944 
4945 		if (strcmp(PQgetvalue(res, i, i_typisdefined), "t") == 0)
4946 			tyinfo[i].isDefined = true;
4947 		else
4948 			tyinfo[i].isDefined = false;
4949 
4950 		if (strcmp(PQgetvalue(res, i, i_isarray), "t") == 0)
4951 			tyinfo[i].isArray = true;
4952 		else
4953 			tyinfo[i].isArray = false;
4954 
4955 		/* Decide whether we want to dump it */
4956 		selectDumpableType(&tyinfo[i], fout);
4957 
4958 		/* Do not try to dump ACL if no ACL exists. */
4959 		if (PQgetisnull(res, i, i_typacl) && PQgetisnull(res, i, i_rtypacl) &&
4960 			PQgetisnull(res, i, i_inittypacl) &&
4961 			PQgetisnull(res, i, i_initrtypacl))
4962 			tyinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
4963 
4964 		/*
4965 		 * If it's a domain, fetch info about its constraints, if any
4966 		 */
4967 		tyinfo[i].nDomChecks = 0;
4968 		tyinfo[i].domChecks = NULL;
4969 		if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
4970 			tyinfo[i].typtype == TYPTYPE_DOMAIN)
4971 			getDomainConstraints(fout, &(tyinfo[i]));
4972 
4973 		/*
4974 		 * If it's a base type, make a DumpableObject representing a shell
4975 		 * definition of the type.  We will need to dump that ahead of the I/O
4976 		 * functions for the type.  Similarly, range types need a shell
4977 		 * definition in case they have a canonicalize function.
4978 		 *
4979 		 * Note: the shell type doesn't have a catId.  You might think it
4980 		 * should copy the base type's catId, but then it might capture the
4981 		 * pg_depend entries for the type, which we don't want.
4982 		 */
4983 		if ((tyinfo[i].dobj.dump & DUMP_COMPONENT_DEFINITION) &&
4984 			(tyinfo[i].typtype == TYPTYPE_BASE ||
4985 			 tyinfo[i].typtype == TYPTYPE_RANGE))
4986 		{
4987 			stinfo = (ShellTypeInfo *) pg_malloc(sizeof(ShellTypeInfo));
4988 			stinfo->dobj.objType = DO_SHELL_TYPE;
4989 			stinfo->dobj.catId = nilCatalogId;
4990 			AssignDumpId(&stinfo->dobj);
4991 			stinfo->dobj.name = pg_strdup(tyinfo[i].dobj.name);
4992 			stinfo->dobj.namespace = tyinfo[i].dobj.namespace;
4993 			stinfo->baseType = &(tyinfo[i]);
4994 			tyinfo[i].shellType = stinfo;
4995 
4996 			/*
4997 			 * Initially mark the shell type as not to be dumped.  We'll only
4998 			 * dump it if the I/O or canonicalize functions need to be dumped;
4999 			 * this is taken care of while sorting dependencies.
5000 			 */
5001 			stinfo->dobj.dump = DUMP_COMPONENT_NONE;
5002 		}
5003 
5004 		if (strlen(tyinfo[i].rolname) == 0)
5005 			write_msg(NULL, "WARNING: owner of data type \"%s\" appears to be invalid\n",
5006 					  tyinfo[i].dobj.name);
5007 	}
5008 
5009 	*numTypes = ntups;
5010 
5011 	PQclear(res);
5012 
5013 	destroyPQExpBuffer(query);
5014 
5015 	return tyinfo;
5016 }
5017 
5018 /*
5019  * getOperators:
5020  *	  read all operators in the system catalogs and return them in the
5021  * OprInfo* structure
5022  *
5023  *	numOprs is set to the number of operators read in
5024  */
5025 OprInfo *
getOperators(Archive * fout,int * numOprs)5026 getOperators(Archive *fout, int *numOprs)
5027 {
5028 	PGresult   *res;
5029 	int			ntups;
5030 	int			i;
5031 	PQExpBuffer query = createPQExpBuffer();
5032 	OprInfo    *oprinfo;
5033 	int			i_tableoid;
5034 	int			i_oid;
5035 	int			i_oprname;
5036 	int			i_oprnamespace;
5037 	int			i_rolname;
5038 	int			i_oprkind;
5039 	int			i_oprcode;
5040 
5041 	/*
5042 	 * find all operators, including builtin operators; we filter out
5043 	 * system-defined operators at dump-out time.
5044 	 */
5045 
5046 	appendPQExpBuffer(query, "SELECT tableoid, oid, oprname, "
5047 					  "oprnamespace, "
5048 					  "(%s oprowner) AS rolname, "
5049 					  "oprkind, "
5050 					  "oprcode::oid AS oprcode "
5051 					  "FROM pg_operator",
5052 					  username_subquery);
5053 
5054 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5055 
5056 	ntups = PQntuples(res);
5057 	*numOprs = ntups;
5058 
5059 	oprinfo = (OprInfo *) pg_malloc(ntups * sizeof(OprInfo));
5060 
5061 	i_tableoid = PQfnumber(res, "tableoid");
5062 	i_oid = PQfnumber(res, "oid");
5063 	i_oprname = PQfnumber(res, "oprname");
5064 	i_oprnamespace = PQfnumber(res, "oprnamespace");
5065 	i_rolname = PQfnumber(res, "rolname");
5066 	i_oprkind = PQfnumber(res, "oprkind");
5067 	i_oprcode = PQfnumber(res, "oprcode");
5068 
5069 	for (i = 0; i < ntups; i++)
5070 	{
5071 		oprinfo[i].dobj.objType = DO_OPERATOR;
5072 		oprinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5073 		oprinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5074 		AssignDumpId(&oprinfo[i].dobj);
5075 		oprinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_oprname));
5076 		oprinfo[i].dobj.namespace =
5077 			findNamespace(fout,
5078 						  atooid(PQgetvalue(res, i, i_oprnamespace)));
5079 		oprinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5080 		oprinfo[i].oprkind = (PQgetvalue(res, i, i_oprkind))[0];
5081 		oprinfo[i].oprcode = atooid(PQgetvalue(res, i, i_oprcode));
5082 
5083 		/* Decide whether we want to dump it */
5084 		selectDumpableObject(&(oprinfo[i].dobj), fout);
5085 
5086 		/* Operators do not currently have ACLs. */
5087 		oprinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5088 
5089 		if (strlen(oprinfo[i].rolname) == 0)
5090 			write_msg(NULL, "WARNING: owner of operator \"%s\" appears to be invalid\n",
5091 					  oprinfo[i].dobj.name);
5092 	}
5093 
5094 	PQclear(res);
5095 
5096 	destroyPQExpBuffer(query);
5097 
5098 	return oprinfo;
5099 }
5100 
5101 /*
5102  * getCollations:
5103  *	  read all collations in the system catalogs and return them in the
5104  * CollInfo* structure
5105  *
5106  *	numCollations is set to the number of collations read in
5107  */
5108 CollInfo *
getCollations(Archive * fout,int * numCollations)5109 getCollations(Archive *fout, int *numCollations)
5110 {
5111 	PGresult   *res;
5112 	int			ntups;
5113 	int			i;
5114 	PQExpBuffer query;
5115 	CollInfo   *collinfo;
5116 	int			i_tableoid;
5117 	int			i_oid;
5118 	int			i_collname;
5119 	int			i_collnamespace;
5120 	int			i_rolname;
5121 
5122 	/* Collations didn't exist pre-9.1 */
5123 	if (fout->remoteVersion < 90100)
5124 	{
5125 		*numCollations = 0;
5126 		return NULL;
5127 	}
5128 
5129 	query = createPQExpBuffer();
5130 
5131 	/*
5132 	 * find all collations, including builtin collations; we filter out
5133 	 * system-defined collations at dump-out time.
5134 	 */
5135 
5136 	appendPQExpBuffer(query, "SELECT tableoid, oid, collname, "
5137 					  "collnamespace, "
5138 					  "(%s collowner) AS rolname "
5139 					  "FROM pg_collation",
5140 					  username_subquery);
5141 
5142 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5143 
5144 	ntups = PQntuples(res);
5145 	*numCollations = ntups;
5146 
5147 	collinfo = (CollInfo *) pg_malloc(ntups * sizeof(CollInfo));
5148 
5149 	i_tableoid = PQfnumber(res, "tableoid");
5150 	i_oid = PQfnumber(res, "oid");
5151 	i_collname = PQfnumber(res, "collname");
5152 	i_collnamespace = PQfnumber(res, "collnamespace");
5153 	i_rolname = PQfnumber(res, "rolname");
5154 
5155 	for (i = 0; i < ntups; i++)
5156 	{
5157 		collinfo[i].dobj.objType = DO_COLLATION;
5158 		collinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5159 		collinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5160 		AssignDumpId(&collinfo[i].dobj);
5161 		collinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_collname));
5162 		collinfo[i].dobj.namespace =
5163 			findNamespace(fout,
5164 						  atooid(PQgetvalue(res, i, i_collnamespace)));
5165 		collinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5166 
5167 		/* Decide whether we want to dump it */
5168 		selectDumpableObject(&(collinfo[i].dobj), fout);
5169 
5170 		/* Collations do not currently have ACLs. */
5171 		collinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5172 	}
5173 
5174 	PQclear(res);
5175 
5176 	destroyPQExpBuffer(query);
5177 
5178 	return collinfo;
5179 }
5180 
5181 /*
5182  * getConversions:
5183  *	  read all conversions in the system catalogs and return them in the
5184  * ConvInfo* structure
5185  *
5186  *	numConversions is set to the number of conversions read in
5187  */
5188 ConvInfo *
getConversions(Archive * fout,int * numConversions)5189 getConversions(Archive *fout, int *numConversions)
5190 {
5191 	PGresult   *res;
5192 	int			ntups;
5193 	int			i;
5194 	PQExpBuffer query;
5195 	ConvInfo   *convinfo;
5196 	int			i_tableoid;
5197 	int			i_oid;
5198 	int			i_conname;
5199 	int			i_connamespace;
5200 	int			i_rolname;
5201 
5202 	query = createPQExpBuffer();
5203 
5204 	/*
5205 	 * find all conversions, including builtin conversions; we filter out
5206 	 * system-defined conversions at dump-out time.
5207 	 */
5208 
5209 	appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
5210 					  "connamespace, "
5211 					  "(%s conowner) AS rolname "
5212 					  "FROM pg_conversion",
5213 					  username_subquery);
5214 
5215 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5216 
5217 	ntups = PQntuples(res);
5218 	*numConversions = ntups;
5219 
5220 	convinfo = (ConvInfo *) pg_malloc(ntups * sizeof(ConvInfo));
5221 
5222 	i_tableoid = PQfnumber(res, "tableoid");
5223 	i_oid = PQfnumber(res, "oid");
5224 	i_conname = PQfnumber(res, "conname");
5225 	i_connamespace = PQfnumber(res, "connamespace");
5226 	i_rolname = PQfnumber(res, "rolname");
5227 
5228 	for (i = 0; i < ntups; i++)
5229 	{
5230 		convinfo[i].dobj.objType = DO_CONVERSION;
5231 		convinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5232 		convinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5233 		AssignDumpId(&convinfo[i].dobj);
5234 		convinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
5235 		convinfo[i].dobj.namespace =
5236 			findNamespace(fout,
5237 						  atooid(PQgetvalue(res, i, i_connamespace)));
5238 		convinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5239 
5240 		/* Decide whether we want to dump it */
5241 		selectDumpableObject(&(convinfo[i].dobj), fout);
5242 
5243 		/* Conversions do not currently have ACLs. */
5244 		convinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5245 	}
5246 
5247 	PQclear(res);
5248 
5249 	destroyPQExpBuffer(query);
5250 
5251 	return convinfo;
5252 }
5253 
5254 /*
5255  * getAccessMethods:
5256  *	  read all user-defined access methods in the system catalogs and return
5257  *	  them in the AccessMethodInfo* structure
5258  *
5259  *	numAccessMethods is set to the number of access methods read in
5260  */
5261 AccessMethodInfo *
getAccessMethods(Archive * fout,int * numAccessMethods)5262 getAccessMethods(Archive *fout, int *numAccessMethods)
5263 {
5264 	PGresult   *res;
5265 	int			ntups;
5266 	int			i;
5267 	PQExpBuffer query;
5268 	AccessMethodInfo *aminfo;
5269 	int			i_tableoid;
5270 	int			i_oid;
5271 	int			i_amname;
5272 	int			i_amhandler;
5273 	int			i_amtype;
5274 
5275 	/* Before 9.6, there are no user-defined access methods */
5276 	if (fout->remoteVersion < 90600)
5277 	{
5278 		*numAccessMethods = 0;
5279 		return NULL;
5280 	}
5281 
5282 	query = createPQExpBuffer();
5283 
5284 	/* Select all access methods from pg_am table */
5285 	appendPQExpBuffer(query, "SELECT tableoid, oid, amname, amtype, "
5286 					  "amhandler::pg_catalog.regproc AS amhandler "
5287 					  "FROM pg_am");
5288 
5289 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5290 
5291 	ntups = PQntuples(res);
5292 	*numAccessMethods = ntups;
5293 
5294 	aminfo = (AccessMethodInfo *) pg_malloc(ntups * sizeof(AccessMethodInfo));
5295 
5296 	i_tableoid = PQfnumber(res, "tableoid");
5297 	i_oid = PQfnumber(res, "oid");
5298 	i_amname = PQfnumber(res, "amname");
5299 	i_amhandler = PQfnumber(res, "amhandler");
5300 	i_amtype = PQfnumber(res, "amtype");
5301 
5302 	for (i = 0; i < ntups; i++)
5303 	{
5304 		aminfo[i].dobj.objType = DO_ACCESS_METHOD;
5305 		aminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5306 		aminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5307 		AssignDumpId(&aminfo[i].dobj);
5308 		aminfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_amname));
5309 		aminfo[i].dobj.namespace = NULL;
5310 		aminfo[i].amhandler = pg_strdup(PQgetvalue(res, i, i_amhandler));
5311 		aminfo[i].amtype = *(PQgetvalue(res, i, i_amtype));
5312 
5313 		/* Decide whether we want to dump it */
5314 		selectDumpableAccessMethod(&(aminfo[i]), fout);
5315 
5316 		/* Access methods do not currently have ACLs. */
5317 		aminfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5318 	}
5319 
5320 	PQclear(res);
5321 
5322 	destroyPQExpBuffer(query);
5323 
5324 	return aminfo;
5325 }
5326 
5327 
5328 /*
5329  * getOpclasses:
5330  *	  read all opclasses in the system catalogs and return them in the
5331  * OpclassInfo* structure
5332  *
5333  *	numOpclasses is set to the number of opclasses read in
5334  */
5335 OpclassInfo *
getOpclasses(Archive * fout,int * numOpclasses)5336 getOpclasses(Archive *fout, int *numOpclasses)
5337 {
5338 	PGresult   *res;
5339 	int			ntups;
5340 	int			i;
5341 	PQExpBuffer query = createPQExpBuffer();
5342 	OpclassInfo *opcinfo;
5343 	int			i_tableoid;
5344 	int			i_oid;
5345 	int			i_opcname;
5346 	int			i_opcnamespace;
5347 	int			i_rolname;
5348 
5349 	/*
5350 	 * find all opclasses, including builtin opclasses; we filter out
5351 	 * system-defined opclasses at dump-out time.
5352 	 */
5353 
5354 	appendPQExpBuffer(query, "SELECT tableoid, oid, opcname, "
5355 					  "opcnamespace, "
5356 					  "(%s opcowner) AS rolname "
5357 					  "FROM pg_opclass",
5358 					  username_subquery);
5359 
5360 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5361 
5362 	ntups = PQntuples(res);
5363 	*numOpclasses = ntups;
5364 
5365 	opcinfo = (OpclassInfo *) pg_malloc(ntups * sizeof(OpclassInfo));
5366 
5367 	i_tableoid = PQfnumber(res, "tableoid");
5368 	i_oid = PQfnumber(res, "oid");
5369 	i_opcname = PQfnumber(res, "opcname");
5370 	i_opcnamespace = PQfnumber(res, "opcnamespace");
5371 	i_rolname = PQfnumber(res, "rolname");
5372 
5373 	for (i = 0; i < ntups; i++)
5374 	{
5375 		opcinfo[i].dobj.objType = DO_OPCLASS;
5376 		opcinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5377 		opcinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5378 		AssignDumpId(&opcinfo[i].dobj);
5379 		opcinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opcname));
5380 		opcinfo[i].dobj.namespace =
5381 			findNamespace(fout,
5382 						  atooid(PQgetvalue(res, i, i_opcnamespace)));
5383 		opcinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5384 
5385 		/* Decide whether we want to dump it */
5386 		selectDumpableObject(&(opcinfo[i].dobj), fout);
5387 
5388 		/* Op Classes do not currently have ACLs. */
5389 		opcinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5390 
5391 		if (strlen(opcinfo[i].rolname) == 0)
5392 			write_msg(NULL, "WARNING: owner of operator class \"%s\" appears to be invalid\n",
5393 					  opcinfo[i].dobj.name);
5394 	}
5395 
5396 	PQclear(res);
5397 
5398 	destroyPQExpBuffer(query);
5399 
5400 	return opcinfo;
5401 }
5402 
5403 /*
5404  * getOpfamilies:
5405  *	  read all opfamilies in the system catalogs and return them in the
5406  * OpfamilyInfo* structure
5407  *
5408  *	numOpfamilies is set to the number of opfamilies read in
5409  */
5410 OpfamilyInfo *
getOpfamilies(Archive * fout,int * numOpfamilies)5411 getOpfamilies(Archive *fout, int *numOpfamilies)
5412 {
5413 	PGresult   *res;
5414 	int			ntups;
5415 	int			i;
5416 	PQExpBuffer query;
5417 	OpfamilyInfo *opfinfo;
5418 	int			i_tableoid;
5419 	int			i_oid;
5420 	int			i_opfname;
5421 	int			i_opfnamespace;
5422 	int			i_rolname;
5423 
5424 	/* Before 8.3, there is no separate concept of opfamilies */
5425 	if (fout->remoteVersion < 80300)
5426 	{
5427 		*numOpfamilies = 0;
5428 		return NULL;
5429 	}
5430 
5431 	query = createPQExpBuffer();
5432 
5433 	/*
5434 	 * find all opfamilies, including builtin opfamilies; we filter out
5435 	 * system-defined opfamilies at dump-out time.
5436 	 */
5437 
5438 	appendPQExpBuffer(query, "SELECT tableoid, oid, opfname, "
5439 					  "opfnamespace, "
5440 					  "(%s opfowner) AS rolname "
5441 					  "FROM pg_opfamily",
5442 					  username_subquery);
5443 
5444 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5445 
5446 	ntups = PQntuples(res);
5447 	*numOpfamilies = ntups;
5448 
5449 	opfinfo = (OpfamilyInfo *) pg_malloc(ntups * sizeof(OpfamilyInfo));
5450 
5451 	i_tableoid = PQfnumber(res, "tableoid");
5452 	i_oid = PQfnumber(res, "oid");
5453 	i_opfname = PQfnumber(res, "opfname");
5454 	i_opfnamespace = PQfnumber(res, "opfnamespace");
5455 	i_rolname = PQfnumber(res, "rolname");
5456 
5457 	for (i = 0; i < ntups; i++)
5458 	{
5459 		opfinfo[i].dobj.objType = DO_OPFAMILY;
5460 		opfinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5461 		opfinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5462 		AssignDumpId(&opfinfo[i].dobj);
5463 		opfinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_opfname));
5464 		opfinfo[i].dobj.namespace =
5465 			findNamespace(fout,
5466 						  atooid(PQgetvalue(res, i, i_opfnamespace)));
5467 		opfinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5468 
5469 		/* Decide whether we want to dump it */
5470 		selectDumpableObject(&(opfinfo[i].dobj), fout);
5471 
5472 		/* Extensions do not currently have ACLs. */
5473 		opfinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5474 
5475 		if (strlen(opfinfo[i].rolname) == 0)
5476 			write_msg(NULL, "WARNING: owner of operator family \"%s\" appears to be invalid\n",
5477 					  opfinfo[i].dobj.name);
5478 	}
5479 
5480 	PQclear(res);
5481 
5482 	destroyPQExpBuffer(query);
5483 
5484 	return opfinfo;
5485 }
5486 
5487 /*
5488  * getAggregates:
5489  *	  read all the user-defined aggregates in the system catalogs and
5490  * return them in the AggInfo* structure
5491  *
5492  * numAggs is set to the number of aggregates read in
5493  */
5494 AggInfo *
getAggregates(Archive * fout,int * numAggs)5495 getAggregates(Archive *fout, int *numAggs)
5496 {
5497 	DumpOptions *dopt = fout->dopt;
5498 	PGresult   *res;
5499 	int			ntups;
5500 	int			i;
5501 	PQExpBuffer query = createPQExpBuffer();
5502 	AggInfo    *agginfo;
5503 	int			i_tableoid;
5504 	int			i_oid;
5505 	int			i_aggname;
5506 	int			i_aggnamespace;
5507 	int			i_pronargs;
5508 	int			i_proargtypes;
5509 	int			i_rolname;
5510 	int			i_aggacl;
5511 	int			i_raggacl;
5512 	int			i_initaggacl;
5513 	int			i_initraggacl;
5514 
5515 	/*
5516 	 * Find all interesting aggregates.  See comment in getFuncs() for the
5517 	 * rationale behind the filtering logic.
5518 	 */
5519 	if (fout->remoteVersion >= 90600)
5520 	{
5521 		PQExpBuffer acl_subquery = createPQExpBuffer();
5522 		PQExpBuffer racl_subquery = createPQExpBuffer();
5523 		PQExpBuffer initacl_subquery = createPQExpBuffer();
5524 		PQExpBuffer initracl_subquery = createPQExpBuffer();
5525 		const char *agg_check;
5526 
5527 		buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
5528 						initracl_subquery, "p.proacl", "p.proowner", "'f'",
5529 						dopt->binary_upgrade);
5530 
5531 		agg_check = (fout->remoteVersion >= 110000 ? "p.prokind = 'a'"
5532 					 : "p.proisagg");
5533 
5534 		appendPQExpBuffer(query, "SELECT p.tableoid, p.oid, "
5535 						  "p.proname AS aggname, "
5536 						  "p.pronamespace AS aggnamespace, "
5537 						  "p.pronargs, p.proargtypes, "
5538 						  "(%s p.proowner) AS rolname, "
5539 						  "%s AS aggacl, "
5540 						  "%s AS raggacl, "
5541 						  "%s AS initaggacl, "
5542 						  "%s AS initraggacl "
5543 						  "FROM pg_proc p "
5544 						  "LEFT JOIN pg_init_privs pip ON "
5545 						  "(p.oid = pip.objoid "
5546 						  "AND pip.classoid = 'pg_proc'::regclass "
5547 						  "AND pip.objsubid = 0) "
5548 						  "WHERE %s AND ("
5549 						  "p.pronamespace != "
5550 						  "(SELECT oid FROM pg_namespace "
5551 						  "WHERE nspname = 'pg_catalog') OR "
5552 						  "p.proacl IS DISTINCT FROM pip.initprivs",
5553 						  username_subquery,
5554 						  acl_subquery->data,
5555 						  racl_subquery->data,
5556 						  initacl_subquery->data,
5557 						  initracl_subquery->data,
5558 						  agg_check);
5559 		if (dopt->binary_upgrade)
5560 			appendPQExpBufferStr(query,
5561 								 " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
5562 								 "classid = 'pg_proc'::regclass AND "
5563 								 "objid = p.oid AND "
5564 								 "refclassid = 'pg_extension'::regclass AND "
5565 								 "deptype = 'e')");
5566 		appendPQExpBufferChar(query, ')');
5567 
5568 		destroyPQExpBuffer(acl_subquery);
5569 		destroyPQExpBuffer(racl_subquery);
5570 		destroyPQExpBuffer(initacl_subquery);
5571 		destroyPQExpBuffer(initracl_subquery);
5572 	}
5573 	else if (fout->remoteVersion >= 80200)
5574 	{
5575 		appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
5576 						  "pronamespace AS aggnamespace, "
5577 						  "pronargs, proargtypes, "
5578 						  "(%s proowner) AS rolname, "
5579 						  "proacl AS aggacl, "
5580 						  "NULL AS raggacl, "
5581 						  "NULL AS initaggacl, NULL AS initraggacl "
5582 						  "FROM pg_proc p "
5583 						  "WHERE proisagg AND ("
5584 						  "pronamespace != "
5585 						  "(SELECT oid FROM pg_namespace "
5586 						  "WHERE nspname = 'pg_catalog')",
5587 						  username_subquery);
5588 		if (dopt->binary_upgrade && fout->remoteVersion >= 90100)
5589 			appendPQExpBufferStr(query,
5590 								 " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
5591 								 "classid = 'pg_proc'::regclass AND "
5592 								 "objid = p.oid AND "
5593 								 "refclassid = 'pg_extension'::regclass AND "
5594 								 "deptype = 'e')");
5595 		appendPQExpBufferChar(query, ')');
5596 	}
5597 	else
5598 	{
5599 		appendPQExpBuffer(query, "SELECT tableoid, oid, proname AS aggname, "
5600 						  "pronamespace AS aggnamespace, "
5601 						  "CASE WHEN proargtypes[0] = 'pg_catalog.\"any\"'::pg_catalog.regtype THEN 0 ELSE 1 END AS pronargs, "
5602 						  "proargtypes, "
5603 						  "(%s proowner) AS rolname, "
5604 						  "proacl AS aggacl, "
5605 						  "NULL AS raggacl, "
5606 						  "NULL AS initaggacl, NULL AS initraggacl "
5607 						  "FROM pg_proc "
5608 						  "WHERE proisagg "
5609 						  "AND pronamespace != "
5610 						  "(SELECT oid FROM pg_namespace WHERE nspname = 'pg_catalog')",
5611 						  username_subquery);
5612 	}
5613 
5614 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5615 
5616 	ntups = PQntuples(res);
5617 	*numAggs = ntups;
5618 
5619 	agginfo = (AggInfo *) pg_malloc(ntups * sizeof(AggInfo));
5620 
5621 	i_tableoid = PQfnumber(res, "tableoid");
5622 	i_oid = PQfnumber(res, "oid");
5623 	i_aggname = PQfnumber(res, "aggname");
5624 	i_aggnamespace = PQfnumber(res, "aggnamespace");
5625 	i_pronargs = PQfnumber(res, "pronargs");
5626 	i_proargtypes = PQfnumber(res, "proargtypes");
5627 	i_rolname = PQfnumber(res, "rolname");
5628 	i_aggacl = PQfnumber(res, "aggacl");
5629 	i_raggacl = PQfnumber(res, "raggacl");
5630 	i_initaggacl = PQfnumber(res, "initaggacl");
5631 	i_initraggacl = PQfnumber(res, "initraggacl");
5632 
5633 	for (i = 0; i < ntups; i++)
5634 	{
5635 		agginfo[i].aggfn.dobj.objType = DO_AGG;
5636 		agginfo[i].aggfn.dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5637 		agginfo[i].aggfn.dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5638 		AssignDumpId(&agginfo[i].aggfn.dobj);
5639 		agginfo[i].aggfn.dobj.name = pg_strdup(PQgetvalue(res, i, i_aggname));
5640 		agginfo[i].aggfn.dobj.namespace =
5641 			findNamespace(fout,
5642 						  atooid(PQgetvalue(res, i, i_aggnamespace)));
5643 		agginfo[i].aggfn.rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5644 		if (strlen(agginfo[i].aggfn.rolname) == 0)
5645 			write_msg(NULL, "WARNING: owner of aggregate function \"%s\" appears to be invalid\n",
5646 					  agginfo[i].aggfn.dobj.name);
5647 		agginfo[i].aggfn.lang = InvalidOid; /* not currently interesting */
5648 		agginfo[i].aggfn.prorettype = InvalidOid;	/* not saved */
5649 		agginfo[i].aggfn.proacl = pg_strdup(PQgetvalue(res, i, i_aggacl));
5650 		agginfo[i].aggfn.rproacl = pg_strdup(PQgetvalue(res, i, i_raggacl));
5651 		agginfo[i].aggfn.initproacl = pg_strdup(PQgetvalue(res, i, i_initaggacl));
5652 		agginfo[i].aggfn.initrproacl = pg_strdup(PQgetvalue(res, i, i_initraggacl));
5653 		agginfo[i].aggfn.nargs = atoi(PQgetvalue(res, i, i_pronargs));
5654 		if (agginfo[i].aggfn.nargs == 0)
5655 			agginfo[i].aggfn.argtypes = NULL;
5656 		else
5657 		{
5658 			agginfo[i].aggfn.argtypes = (Oid *) pg_malloc(agginfo[i].aggfn.nargs * sizeof(Oid));
5659 			parseOidArray(PQgetvalue(res, i, i_proargtypes),
5660 						  agginfo[i].aggfn.argtypes,
5661 						  agginfo[i].aggfn.nargs);
5662 		}
5663 
5664 		/* Decide whether we want to dump it */
5665 		selectDumpableObject(&(agginfo[i].aggfn.dobj), fout);
5666 
5667 		/* Do not try to dump ACL if no ACL exists. */
5668 		if (PQgetisnull(res, i, i_aggacl) && PQgetisnull(res, i, i_raggacl) &&
5669 			PQgetisnull(res, i, i_initaggacl) &&
5670 			PQgetisnull(res, i, i_initraggacl))
5671 			agginfo[i].aggfn.dobj.dump &= ~DUMP_COMPONENT_ACL;
5672 	}
5673 
5674 	PQclear(res);
5675 
5676 	destroyPQExpBuffer(query);
5677 
5678 	return agginfo;
5679 }
5680 
5681 /*
5682  * getFuncs:
5683  *	  read all the user-defined functions in the system catalogs and
5684  * return them in the FuncInfo* structure
5685  *
5686  * numFuncs is set to the number of functions read in
5687  */
5688 FuncInfo *
getFuncs(Archive * fout,int * numFuncs)5689 getFuncs(Archive *fout, int *numFuncs)
5690 {
5691 	DumpOptions *dopt = fout->dopt;
5692 	PGresult   *res;
5693 	int			ntups;
5694 	int			i;
5695 	PQExpBuffer query = createPQExpBuffer();
5696 	FuncInfo   *finfo;
5697 	int			i_tableoid;
5698 	int			i_oid;
5699 	int			i_proname;
5700 	int			i_pronamespace;
5701 	int			i_rolname;
5702 	int			i_prolang;
5703 	int			i_pronargs;
5704 	int			i_proargtypes;
5705 	int			i_prorettype;
5706 	int			i_proacl;
5707 	int			i_rproacl;
5708 	int			i_initproacl;
5709 	int			i_initrproacl;
5710 
5711 	/*
5712 	 * Find all interesting functions.  This is a bit complicated:
5713 	 *
5714 	 * 1. Always exclude aggregates; those are handled elsewhere.
5715 	 *
5716 	 * 2. Always exclude functions that are internally dependent on something
5717 	 * else, since presumably those will be created as a result of creating
5718 	 * the something else.  This currently acts only to suppress constructor
5719 	 * functions for range types (so we only need it in 9.2 and up).  Note
5720 	 * this is OK only because the constructors don't have any dependencies
5721 	 * the range type doesn't have; otherwise we might not get creation
5722 	 * ordering correct.
5723 	 *
5724 	 * 3. Otherwise, we normally exclude functions in pg_catalog.  However, if
5725 	 * they're members of extensions and we are in binary-upgrade mode then
5726 	 * include them, since we want to dump extension members individually in
5727 	 * that mode.  Also, if they are used by casts or transforms then we need
5728 	 * to gather the information about them, though they won't be dumped if
5729 	 * they are built-in.  Also, in 9.6 and up, include functions in
5730 	 * pg_catalog if they have an ACL different from what's shown in
5731 	 * pg_init_privs.
5732 	 */
5733 	if (fout->remoteVersion >= 90600)
5734 	{
5735 		PQExpBuffer acl_subquery = createPQExpBuffer();
5736 		PQExpBuffer racl_subquery = createPQExpBuffer();
5737 		PQExpBuffer initacl_subquery = createPQExpBuffer();
5738 		PQExpBuffer initracl_subquery = createPQExpBuffer();
5739 		const char *not_agg_check;
5740 
5741 		buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
5742 						initracl_subquery, "p.proacl", "p.proowner", "'f'",
5743 						dopt->binary_upgrade);
5744 
5745 		not_agg_check = (fout->remoteVersion >= 110000 ? "p.prokind <> 'a'"
5746 						 : "NOT p.proisagg");
5747 
5748 		appendPQExpBuffer(query,
5749 						  "SELECT p.tableoid, p.oid, p.proname, p.prolang, "
5750 						  "p.pronargs, p.proargtypes, p.prorettype, "
5751 						  "%s AS proacl, "
5752 						  "%s AS rproacl, "
5753 						  "%s AS initproacl, "
5754 						  "%s AS initrproacl, "
5755 						  "p.pronamespace, "
5756 						  "(%s p.proowner) AS rolname "
5757 						  "FROM pg_proc p "
5758 						  "LEFT JOIN pg_init_privs pip ON "
5759 						  "(p.oid = pip.objoid "
5760 						  "AND pip.classoid = 'pg_proc'::regclass "
5761 						  "AND pip.objsubid = 0) "
5762 						  "WHERE %s"
5763 						  "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
5764 						  "WHERE classid = 'pg_proc'::regclass AND "
5765 						  "objid = p.oid AND deptype = 'i')"
5766 						  "\n  AND ("
5767 						  "\n  pronamespace != "
5768 						  "(SELECT oid FROM pg_namespace "
5769 						  "WHERE nspname = 'pg_catalog')"
5770 						  "\n  OR EXISTS (SELECT 1 FROM pg_cast"
5771 						  "\n  WHERE pg_cast.oid > %u "
5772 						  "\n  AND p.oid = pg_cast.castfunc)"
5773 						  "\n  OR EXISTS (SELECT 1 FROM pg_transform"
5774 						  "\n  WHERE pg_transform.oid > %u AND "
5775 						  "\n  (p.oid = pg_transform.trffromsql"
5776 						  "\n  OR p.oid = pg_transform.trftosql))",
5777 						  acl_subquery->data,
5778 						  racl_subquery->data,
5779 						  initacl_subquery->data,
5780 						  initracl_subquery->data,
5781 						  username_subquery,
5782 						  not_agg_check,
5783 						  g_last_builtin_oid,
5784 						  g_last_builtin_oid);
5785 		if (dopt->binary_upgrade)
5786 			appendPQExpBufferStr(query,
5787 								 "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
5788 								 "classid = 'pg_proc'::regclass AND "
5789 								 "objid = p.oid AND "
5790 								 "refclassid = 'pg_extension'::regclass AND "
5791 								 "deptype = 'e')");
5792 		appendPQExpBufferStr(query,
5793 							 "\n  OR p.proacl IS DISTINCT FROM pip.initprivs");
5794 		appendPQExpBufferChar(query, ')');
5795 
5796 		destroyPQExpBuffer(acl_subquery);
5797 		destroyPQExpBuffer(racl_subquery);
5798 		destroyPQExpBuffer(initacl_subquery);
5799 		destroyPQExpBuffer(initracl_subquery);
5800 	}
5801 	else
5802 	{
5803 		appendPQExpBuffer(query,
5804 						  "SELECT tableoid, oid, proname, prolang, "
5805 						  "pronargs, proargtypes, prorettype, proacl, "
5806 						  "NULL as rproacl, "
5807 						  "NULL as initproacl, NULL AS initrproacl, "
5808 						  "pronamespace, "
5809 						  "(%s proowner) AS rolname "
5810 						  "FROM pg_proc p "
5811 						  "WHERE NOT proisagg",
5812 						  username_subquery);
5813 		if (fout->remoteVersion >= 90200)
5814 			appendPQExpBufferStr(query,
5815 								 "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
5816 								 "WHERE classid = 'pg_proc'::regclass AND "
5817 								 "objid = p.oid AND deptype = 'i')");
5818 		appendPQExpBuffer(query,
5819 						  "\n  AND ("
5820 						  "\n  pronamespace != "
5821 						  "(SELECT oid FROM pg_namespace "
5822 						  "WHERE nspname = 'pg_catalog')"
5823 						  "\n  OR EXISTS (SELECT 1 FROM pg_cast"
5824 						  "\n  WHERE pg_cast.oid > '%u'::oid"
5825 						  "\n  AND p.oid = pg_cast.castfunc)",
5826 						  g_last_builtin_oid);
5827 
5828 		if (fout->remoteVersion >= 90500)
5829 			appendPQExpBuffer(query,
5830 							  "\n  OR EXISTS (SELECT 1 FROM pg_transform"
5831 							  "\n  WHERE pg_transform.oid > '%u'::oid"
5832 							  "\n  AND (p.oid = pg_transform.trffromsql"
5833 							  "\n  OR p.oid = pg_transform.trftosql))",
5834 							  g_last_builtin_oid);
5835 
5836 		if (dopt->binary_upgrade && fout->remoteVersion >= 90100)
5837 			appendPQExpBufferStr(query,
5838 								 "\n  OR EXISTS(SELECT 1 FROM pg_depend WHERE "
5839 								 "classid = 'pg_proc'::regclass AND "
5840 								 "objid = p.oid AND "
5841 								 "refclassid = 'pg_extension'::regclass AND "
5842 								 "deptype = 'e')");
5843 		appendPQExpBufferChar(query, ')');
5844 	}
5845 
5846 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
5847 
5848 	ntups = PQntuples(res);
5849 
5850 	*numFuncs = ntups;
5851 
5852 	finfo = (FuncInfo *) pg_malloc0(ntups * sizeof(FuncInfo));
5853 
5854 	i_tableoid = PQfnumber(res, "tableoid");
5855 	i_oid = PQfnumber(res, "oid");
5856 	i_proname = PQfnumber(res, "proname");
5857 	i_pronamespace = PQfnumber(res, "pronamespace");
5858 	i_rolname = PQfnumber(res, "rolname");
5859 	i_prolang = PQfnumber(res, "prolang");
5860 	i_pronargs = PQfnumber(res, "pronargs");
5861 	i_proargtypes = PQfnumber(res, "proargtypes");
5862 	i_prorettype = PQfnumber(res, "prorettype");
5863 	i_proacl = PQfnumber(res, "proacl");
5864 	i_rproacl = PQfnumber(res, "rproacl");
5865 	i_initproacl = PQfnumber(res, "initproacl");
5866 	i_initrproacl = PQfnumber(res, "initrproacl");
5867 
5868 	for (i = 0; i < ntups; i++)
5869 	{
5870 		finfo[i].dobj.objType = DO_FUNC;
5871 		finfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
5872 		finfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
5873 		AssignDumpId(&finfo[i].dobj);
5874 		finfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_proname));
5875 		finfo[i].dobj.namespace =
5876 			findNamespace(fout,
5877 						  atooid(PQgetvalue(res, i, i_pronamespace)));
5878 		finfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
5879 		finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
5880 		finfo[i].prorettype = atooid(PQgetvalue(res, i, i_prorettype));
5881 		finfo[i].proacl = pg_strdup(PQgetvalue(res, i, i_proacl));
5882 		finfo[i].rproacl = pg_strdup(PQgetvalue(res, i, i_rproacl));
5883 		finfo[i].initproacl = pg_strdup(PQgetvalue(res, i, i_initproacl));
5884 		finfo[i].initrproacl = pg_strdup(PQgetvalue(res, i, i_initrproacl));
5885 		finfo[i].nargs = atoi(PQgetvalue(res, i, i_pronargs));
5886 		if (finfo[i].nargs == 0)
5887 			finfo[i].argtypes = NULL;
5888 		else
5889 		{
5890 			finfo[i].argtypes = (Oid *) pg_malloc(finfo[i].nargs * sizeof(Oid));
5891 			parseOidArray(PQgetvalue(res, i, i_proargtypes),
5892 						  finfo[i].argtypes, finfo[i].nargs);
5893 		}
5894 
5895 		/* Decide whether we want to dump it */
5896 		selectDumpableObject(&(finfo[i].dobj), fout);
5897 
5898 		/* Do not try to dump ACL if no ACL exists. */
5899 		if (PQgetisnull(res, i, i_proacl) && PQgetisnull(res, i, i_rproacl) &&
5900 			PQgetisnull(res, i, i_initproacl) &&
5901 			PQgetisnull(res, i, i_initrproacl))
5902 			finfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
5903 
5904 		if (strlen(finfo[i].rolname) == 0)
5905 			write_msg(NULL,
5906 					  "WARNING: owner of function \"%s\" appears to be invalid\n",
5907 					  finfo[i].dobj.name);
5908 	}
5909 
5910 	PQclear(res);
5911 
5912 	destroyPQExpBuffer(query);
5913 
5914 	return finfo;
5915 }
5916 
5917 /*
5918  * getTables
5919  *	  read all the tables (no indexes)
5920  * in the system catalogs return them in the TableInfo* structure
5921  *
5922  * numTables is set to the number of tables read in
5923  */
5924 TableInfo *
getTables(Archive * fout,int * numTables)5925 getTables(Archive *fout, int *numTables)
5926 {
5927 	DumpOptions *dopt = fout->dopt;
5928 	PGresult   *res;
5929 	int			ntups;
5930 	int			i;
5931 	PQExpBuffer query = createPQExpBuffer();
5932 	TableInfo  *tblinfo;
5933 	int			i_reltableoid;
5934 	int			i_reloid;
5935 	int			i_relname;
5936 	int			i_relnamespace;
5937 	int			i_relkind;
5938 	int			i_relacl;
5939 	int			i_rrelacl;
5940 	int			i_initrelacl;
5941 	int			i_initrrelacl;
5942 	int			i_rolname;
5943 	int			i_relchecks;
5944 	int			i_relhastriggers;
5945 	int			i_relhasindex;
5946 	int			i_relhasrules;
5947 	int			i_relrowsec;
5948 	int			i_relforcerowsec;
5949 	int			i_relhasoids;
5950 	int			i_relfrozenxid;
5951 	int			i_relminmxid;
5952 	int			i_toastoid;
5953 	int			i_toastfrozenxid;
5954 	int			i_toastminmxid;
5955 	int			i_relpersistence;
5956 	int			i_relispopulated;
5957 	int			i_relreplident;
5958 	int			i_owning_tab;
5959 	int			i_owning_col;
5960 	int			i_reltablespace;
5961 	int			i_reloptions;
5962 	int			i_checkoption;
5963 	int			i_toastreloptions;
5964 	int			i_reloftype;
5965 	int			i_relpages;
5966 	int			i_is_identity_sequence;
5967 	int			i_changed_acl;
5968 	int			i_partkeydef;
5969 	int			i_ispartition;
5970 	int			i_partbound;
5971 
5972 	/*
5973 	 * Find all the tables and table-like objects.
5974 	 *
5975 	 * We include system catalogs, so that we can work if a user table is
5976 	 * defined to inherit from a system catalog (pretty weird, but...)
5977 	 *
5978 	 * We ignore relations that are not ordinary tables, sequences, views,
5979 	 * materialized views, composite types, or foreign tables.
5980 	 *
5981 	 * Composite-type table entries won't be dumped as such, but we have to
5982 	 * make a DumpableObject for them so that we can track dependencies of the
5983 	 * composite type (pg_depend entries for columns of the composite type
5984 	 * link to the pg_class entry not the pg_type entry).
5985 	 *
5986 	 * Note: in this phase we should collect only a minimal amount of
5987 	 * information about each table, basically just enough to decide if it is
5988 	 * interesting. We must fetch all tables in this phase because otherwise
5989 	 * we cannot correctly identify inherited columns, owned sequences, etc.
5990 	 */
5991 
5992 	if (fout->remoteVersion >= 90600)
5993 	{
5994 		char	   *partkeydef = "NULL";
5995 		char	   *ispartition = "false";
5996 		char	   *partbound = "NULL";
5997 
5998 		PQExpBuffer acl_subquery = createPQExpBuffer();
5999 		PQExpBuffer racl_subquery = createPQExpBuffer();
6000 		PQExpBuffer initacl_subquery = createPQExpBuffer();
6001 		PQExpBuffer initracl_subquery = createPQExpBuffer();
6002 
6003 		PQExpBuffer attacl_subquery = createPQExpBuffer();
6004 		PQExpBuffer attracl_subquery = createPQExpBuffer();
6005 		PQExpBuffer attinitacl_subquery = createPQExpBuffer();
6006 		PQExpBuffer attinitracl_subquery = createPQExpBuffer();
6007 
6008 		/*
6009 		 * Collect the information about any partitioned tables, which were
6010 		 * added in PG10.
6011 		 */
6012 
6013 		if (fout->remoteVersion >= 100000)
6014 		{
6015 			partkeydef = "pg_get_partkeydef(c.oid)";
6016 			ispartition = "c.relispartition";
6017 			partbound = "pg_get_expr(c.relpartbound, c.oid)";
6018 		}
6019 
6020 		/*
6021 		 * Left join to pick up dependency info linking sequences to their
6022 		 * owning column, if any (note this dependency is AUTO as of 8.2)
6023 		 *
6024 		 * Left join to detect if any privileges are still as-set-at-init, in
6025 		 * which case we won't dump out ACL commands for those.
6026 		 */
6027 
6028 		buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
6029 						initracl_subquery, "c.relacl", "c.relowner",
6030 						"CASE WHEN c.relkind = " CppAsString2(RELKIND_SEQUENCE)
6031 						" THEN 's' ELSE 'r' END::\"char\"",
6032 						dopt->binary_upgrade);
6033 
6034 		buildACLQueries(attacl_subquery, attracl_subquery, attinitacl_subquery,
6035 						attinitracl_subquery, "at.attacl", "c.relowner", "'c'",
6036 						dopt->binary_upgrade);
6037 
6038 		appendPQExpBuffer(query,
6039 						  "SELECT c.tableoid, c.oid, c.relname, "
6040 						  "%s AS relacl, %s as rrelacl, "
6041 						  "%s AS initrelacl, %s as initrrelacl, "
6042 						  "c.relkind, c.relnamespace, "
6043 						  "(%s c.relowner) AS rolname, "
6044 						  "c.relchecks, c.relhastriggers, "
6045 						  "c.relhasindex, c.relhasrules, c.relhasoids, "
6046 						  "c.relrowsecurity, c.relforcerowsecurity, "
6047 						  "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
6048 						  "tc.relfrozenxid AS tfrozenxid, "
6049 						  "tc.relminmxid AS tminmxid, "
6050 						  "c.relpersistence, c.relispopulated, "
6051 						  "c.relreplident, c.relpages, "
6052 						  "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6053 						  "d.refobjid AS owning_tab, "
6054 						  "d.refobjsubid AS owning_col, "
6055 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6056 						  "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
6057 						  "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
6058 						  "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
6059 						  "tc.reloptions AS toast_reloptions, "
6060 						  "c.relkind = '%c' AND EXISTS (SELECT 1 FROM pg_depend WHERE classid = 'pg_class'::regclass AND objid = c.oid AND objsubid = 0 AND refclassid = 'pg_class'::regclass AND deptype = 'i') AS is_identity_sequence, "
6061 						  "EXISTS (SELECT 1 FROM pg_attribute at LEFT JOIN pg_init_privs pip ON "
6062 						  "(c.oid = pip.objoid "
6063 						  "AND pip.classoid = 'pg_class'::regclass "
6064 						  "AND pip.objsubid = at.attnum)"
6065 						  "WHERE at.attrelid = c.oid AND ("
6066 						  "%s IS NOT NULL "
6067 						  "OR %s IS NOT NULL "
6068 						  "OR %s IS NOT NULL "
6069 						  "OR %s IS NOT NULL"
6070 						  "))"
6071 						  "AS changed_acl, "
6072 						  "%s AS partkeydef, "
6073 						  "%s AS ispartition, "
6074 						  "%s AS partbound "
6075 						  "FROM pg_class c "
6076 						  "LEFT JOIN pg_depend d ON "
6077 						  "(c.relkind = '%c' AND "
6078 						  "d.classid = c.tableoid AND d.objid = c.oid AND "
6079 						  "d.objsubid = 0 AND "
6080 						  "d.refclassid = c.tableoid AND d.deptype IN ('a', 'i')) "
6081 						  "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6082 						  "LEFT JOIN pg_init_privs pip ON "
6083 						  "(c.oid = pip.objoid "
6084 						  "AND pip.classoid = 'pg_class'::regclass "
6085 						  "AND pip.objsubid = 0) "
6086 						  "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c', '%c') "
6087 						  "ORDER BY c.oid",
6088 						  acl_subquery->data,
6089 						  racl_subquery->data,
6090 						  initacl_subquery->data,
6091 						  initracl_subquery->data,
6092 						  username_subquery,
6093 						  RELKIND_SEQUENCE,
6094 						  attacl_subquery->data,
6095 						  attracl_subquery->data,
6096 						  attinitacl_subquery->data,
6097 						  attinitracl_subquery->data,
6098 						  partkeydef,
6099 						  ispartition,
6100 						  partbound,
6101 						  RELKIND_SEQUENCE,
6102 						  RELKIND_RELATION, RELKIND_SEQUENCE,
6103 						  RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
6104 						  RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE,
6105 						  RELKIND_PARTITIONED_TABLE);
6106 
6107 		destroyPQExpBuffer(acl_subquery);
6108 		destroyPQExpBuffer(racl_subquery);
6109 		destroyPQExpBuffer(initacl_subquery);
6110 		destroyPQExpBuffer(initracl_subquery);
6111 
6112 		destroyPQExpBuffer(attacl_subquery);
6113 		destroyPQExpBuffer(attracl_subquery);
6114 		destroyPQExpBuffer(attinitacl_subquery);
6115 		destroyPQExpBuffer(attinitracl_subquery);
6116 	}
6117 	else if (fout->remoteVersion >= 90500)
6118 	{
6119 		/*
6120 		 * Left join to pick up dependency info linking sequences to their
6121 		 * owning column, if any (note this dependency is AUTO as of 8.2)
6122 		 */
6123 		appendPQExpBuffer(query,
6124 						  "SELECT c.tableoid, c.oid, c.relname, "
6125 						  "c.relacl, NULL as rrelacl, "
6126 						  "NULL AS initrelacl, NULL AS initrrelacl, "
6127 						  "c.relkind, "
6128 						  "c.relnamespace, "
6129 						  "(%s c.relowner) AS rolname, "
6130 						  "c.relchecks, c.relhastriggers, "
6131 						  "c.relhasindex, c.relhasrules, c.relhasoids, "
6132 						  "c.relrowsecurity, c.relforcerowsecurity, "
6133 						  "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
6134 						  "tc.relfrozenxid AS tfrozenxid, "
6135 						  "tc.relminmxid AS tminmxid, "
6136 						  "c.relpersistence, c.relispopulated, "
6137 						  "c.relreplident, c.relpages, "
6138 						  "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6139 						  "d.refobjid AS owning_tab, "
6140 						  "d.refobjsubid AS owning_col, "
6141 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6142 						  "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
6143 						  "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
6144 						  "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
6145 						  "tc.reloptions AS toast_reloptions, "
6146 						  "NULL AS changed_acl, "
6147 						  "NULL AS partkeydef, "
6148 						  "false AS ispartition, "
6149 						  "NULL AS partbound "
6150 						  "FROM pg_class c "
6151 						  "LEFT JOIN pg_depend d ON "
6152 						  "(c.relkind = '%c' AND "
6153 						  "d.classid = c.tableoid AND d.objid = c.oid AND "
6154 						  "d.objsubid = 0 AND "
6155 						  "d.refclassid = c.tableoid AND d.deptype = 'a') "
6156 						  "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6157 						  "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
6158 						  "ORDER BY c.oid",
6159 						  username_subquery,
6160 						  RELKIND_SEQUENCE,
6161 						  RELKIND_RELATION, RELKIND_SEQUENCE,
6162 						  RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
6163 						  RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
6164 	}
6165 	else if (fout->remoteVersion >= 90400)
6166 	{
6167 		/*
6168 		 * Left join to pick up dependency info linking sequences to their
6169 		 * owning column, if any (note this dependency is AUTO as of 8.2)
6170 		 */
6171 		appendPQExpBuffer(query,
6172 						  "SELECT c.tableoid, c.oid, c.relname, "
6173 						  "c.relacl, NULL as rrelacl, "
6174 						  "NULL AS initrelacl, NULL AS initrrelacl, "
6175 						  "c.relkind, "
6176 						  "c.relnamespace, "
6177 						  "(%s c.relowner) AS rolname, "
6178 						  "c.relchecks, c.relhastriggers, "
6179 						  "c.relhasindex, c.relhasrules, c.relhasoids, "
6180 						  "'f'::bool AS relrowsecurity, "
6181 						  "'f'::bool AS relforcerowsecurity, "
6182 						  "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
6183 						  "tc.relfrozenxid AS tfrozenxid, "
6184 						  "tc.relminmxid AS tminmxid, "
6185 						  "c.relpersistence, c.relispopulated, "
6186 						  "c.relreplident, c.relpages, "
6187 						  "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6188 						  "d.refobjid AS owning_tab, "
6189 						  "d.refobjsubid AS owning_col, "
6190 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6191 						  "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
6192 						  "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
6193 						  "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
6194 						  "tc.reloptions AS toast_reloptions, "
6195 						  "NULL AS changed_acl, "
6196 						  "NULL AS partkeydef, "
6197 						  "false AS ispartition, "
6198 						  "NULL AS partbound "
6199 						  "FROM pg_class c "
6200 						  "LEFT JOIN pg_depend d ON "
6201 						  "(c.relkind = '%c' AND "
6202 						  "d.classid = c.tableoid AND d.objid = c.oid AND "
6203 						  "d.objsubid = 0 AND "
6204 						  "d.refclassid = c.tableoid AND d.deptype = 'a') "
6205 						  "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6206 						  "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
6207 						  "ORDER BY c.oid",
6208 						  username_subquery,
6209 						  RELKIND_SEQUENCE,
6210 						  RELKIND_RELATION, RELKIND_SEQUENCE,
6211 						  RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
6212 						  RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
6213 	}
6214 	else if (fout->remoteVersion >= 90300)
6215 	{
6216 		/*
6217 		 * Left join to pick up dependency info linking sequences to their
6218 		 * owning column, if any (note this dependency is AUTO as of 8.2)
6219 		 */
6220 		appendPQExpBuffer(query,
6221 						  "SELECT c.tableoid, c.oid, c.relname, "
6222 						  "c.relacl, NULL as rrelacl, "
6223 						  "NULL AS initrelacl, NULL AS initrrelacl, "
6224 						  "c.relkind, "
6225 						  "c.relnamespace, "
6226 						  "(%s c.relowner) AS rolname, "
6227 						  "c.relchecks, c.relhastriggers, "
6228 						  "c.relhasindex, c.relhasrules, c.relhasoids, "
6229 						  "'f'::bool AS relrowsecurity, "
6230 						  "'f'::bool AS relforcerowsecurity, "
6231 						  "c.relfrozenxid, c.relminmxid, tc.oid AS toid, "
6232 						  "tc.relfrozenxid AS tfrozenxid, "
6233 						  "tc.relminmxid AS tminmxid, "
6234 						  "c.relpersistence, c.relispopulated, "
6235 						  "'d' AS relreplident, c.relpages, "
6236 						  "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6237 						  "d.refobjid AS owning_tab, "
6238 						  "d.refobjsubid AS owning_col, "
6239 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6240 						  "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, "
6241 						  "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text "
6242 						  "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "
6243 						  "tc.reloptions AS toast_reloptions, "
6244 						  "NULL AS changed_acl, "
6245 						  "NULL AS partkeydef, "
6246 						  "false AS ispartition, "
6247 						  "NULL AS partbound "
6248 						  "FROM pg_class c "
6249 						  "LEFT JOIN pg_depend d ON "
6250 						  "(c.relkind = '%c' AND "
6251 						  "d.classid = c.tableoid AND d.objid = c.oid AND "
6252 						  "d.objsubid = 0 AND "
6253 						  "d.refclassid = c.tableoid AND d.deptype = 'a') "
6254 						  "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6255 						  "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
6256 						  "ORDER BY c.oid",
6257 						  username_subquery,
6258 						  RELKIND_SEQUENCE,
6259 						  RELKIND_RELATION, RELKIND_SEQUENCE,
6260 						  RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
6261 						  RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
6262 	}
6263 	else if (fout->remoteVersion >= 90100)
6264 	{
6265 		/*
6266 		 * Left join to pick up dependency info linking sequences to their
6267 		 * owning column, if any (note this dependency is AUTO as of 8.2)
6268 		 */
6269 		appendPQExpBuffer(query,
6270 						  "SELECT c.tableoid, c.oid, c.relname, "
6271 						  "c.relacl, NULL as rrelacl, "
6272 						  "NULL AS initrelacl, NULL AS initrrelacl, "
6273 						  "c.relkind, "
6274 						  "c.relnamespace, "
6275 						  "(%s c.relowner) AS rolname, "
6276 						  "c.relchecks, c.relhastriggers, "
6277 						  "c.relhasindex, c.relhasrules, c.relhasoids, "
6278 						  "'f'::bool AS relrowsecurity, "
6279 						  "'f'::bool AS relforcerowsecurity, "
6280 						  "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
6281 						  "tc.relfrozenxid AS tfrozenxid, "
6282 						  "0 AS tminmxid, "
6283 						  "c.relpersistence, 't' as relispopulated, "
6284 						  "'d' AS relreplident, c.relpages, "
6285 						  "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6286 						  "d.refobjid AS owning_tab, "
6287 						  "d.refobjsubid AS owning_col, "
6288 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6289 						  "c.reloptions AS reloptions, "
6290 						  "tc.reloptions AS toast_reloptions, "
6291 						  "NULL AS changed_acl, "
6292 						  "NULL AS partkeydef, "
6293 						  "false AS ispartition, "
6294 						  "NULL AS partbound "
6295 						  "FROM pg_class c "
6296 						  "LEFT JOIN pg_depend d ON "
6297 						  "(c.relkind = '%c' AND "
6298 						  "d.classid = c.tableoid AND d.objid = c.oid AND "
6299 						  "d.objsubid = 0 AND "
6300 						  "d.refclassid = c.tableoid AND d.deptype = 'a') "
6301 						  "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6302 						  "WHERE c.relkind in ('%c', '%c', '%c', '%c', '%c', '%c') "
6303 						  "ORDER BY c.oid",
6304 						  username_subquery,
6305 						  RELKIND_SEQUENCE,
6306 						  RELKIND_RELATION, RELKIND_SEQUENCE,
6307 						  RELKIND_VIEW, RELKIND_COMPOSITE_TYPE,
6308 						  RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE);
6309 	}
6310 	else if (fout->remoteVersion >= 90000)
6311 	{
6312 		/*
6313 		 * Left join to pick up dependency info linking sequences to their
6314 		 * owning column, if any (note this dependency is AUTO as of 8.2)
6315 		 */
6316 		appendPQExpBuffer(query,
6317 						  "SELECT c.tableoid, c.oid, c.relname, "
6318 						  "c.relacl, NULL as rrelacl, "
6319 						  "NULL AS initrelacl, NULL AS initrrelacl, "
6320 						  "c.relkind, "
6321 						  "c.relnamespace, "
6322 						  "(%s c.relowner) AS rolname, "
6323 						  "c.relchecks, c.relhastriggers, "
6324 						  "c.relhasindex, c.relhasrules, c.relhasoids, "
6325 						  "'f'::bool AS relrowsecurity, "
6326 						  "'f'::bool AS relforcerowsecurity, "
6327 						  "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
6328 						  "tc.relfrozenxid AS tfrozenxid, "
6329 						  "0 AS tminmxid, "
6330 						  "'p' AS relpersistence, 't' as relispopulated, "
6331 						  "'d' AS relreplident, c.relpages, "
6332 						  "CASE WHEN c.reloftype <> 0 THEN c.reloftype::pg_catalog.regtype ELSE NULL END AS reloftype, "
6333 						  "d.refobjid AS owning_tab, "
6334 						  "d.refobjsubid AS owning_col, "
6335 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6336 						  "c.reloptions AS reloptions, "
6337 						  "tc.reloptions AS toast_reloptions, "
6338 						  "NULL AS changed_acl, "
6339 						  "NULL AS partkeydef, "
6340 						  "false AS ispartition, "
6341 						  "NULL AS partbound "
6342 						  "FROM pg_class c "
6343 						  "LEFT JOIN pg_depend d ON "
6344 						  "(c.relkind = '%c' AND "
6345 						  "d.classid = c.tableoid AND d.objid = c.oid AND "
6346 						  "d.objsubid = 0 AND "
6347 						  "d.refclassid = c.tableoid AND d.deptype = 'a') "
6348 						  "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6349 						  "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
6350 						  "ORDER BY c.oid",
6351 						  username_subquery,
6352 						  RELKIND_SEQUENCE,
6353 						  RELKIND_RELATION, RELKIND_SEQUENCE,
6354 						  RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
6355 	}
6356 	else if (fout->remoteVersion >= 80400)
6357 	{
6358 		/*
6359 		 * Left join to pick up dependency info linking sequences to their
6360 		 * owning column, if any (note this dependency is AUTO as of 8.2)
6361 		 */
6362 		appendPQExpBuffer(query,
6363 						  "SELECT c.tableoid, c.oid, c.relname, "
6364 						  "c.relacl, NULL as rrelacl, "
6365 						  "NULL AS initrelacl, NULL AS initrrelacl, "
6366 						  "c.relkind, "
6367 						  "c.relnamespace, "
6368 						  "(%s c.relowner) AS rolname, "
6369 						  "c.relchecks, c.relhastriggers, "
6370 						  "c.relhasindex, c.relhasrules, c.relhasoids, "
6371 						  "'f'::bool AS relrowsecurity, "
6372 						  "'f'::bool AS relforcerowsecurity, "
6373 						  "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
6374 						  "tc.relfrozenxid AS tfrozenxid, "
6375 						  "0 AS tminmxid, "
6376 						  "'p' AS relpersistence, 't' as relispopulated, "
6377 						  "'d' AS relreplident, c.relpages, "
6378 						  "NULL AS reloftype, "
6379 						  "d.refobjid AS owning_tab, "
6380 						  "d.refobjsubid AS owning_col, "
6381 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6382 						  "c.reloptions AS reloptions, "
6383 						  "tc.reloptions AS toast_reloptions, "
6384 						  "NULL AS changed_acl, "
6385 						  "NULL AS partkeydef, "
6386 						  "false AS ispartition, "
6387 						  "NULL AS partbound "
6388 						  "FROM pg_class c "
6389 						  "LEFT JOIN pg_depend d ON "
6390 						  "(c.relkind = '%c' AND "
6391 						  "d.classid = c.tableoid AND d.objid = c.oid AND "
6392 						  "d.objsubid = 0 AND "
6393 						  "d.refclassid = c.tableoid AND d.deptype = 'a') "
6394 						  "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6395 						  "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
6396 						  "ORDER BY c.oid",
6397 						  username_subquery,
6398 						  RELKIND_SEQUENCE,
6399 						  RELKIND_RELATION, RELKIND_SEQUENCE,
6400 						  RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
6401 	}
6402 	else if (fout->remoteVersion >= 80200)
6403 	{
6404 		/*
6405 		 * Left join to pick up dependency info linking sequences to their
6406 		 * owning column, if any (note this dependency is AUTO as of 8.2)
6407 		 */
6408 		appendPQExpBuffer(query,
6409 						  "SELECT c.tableoid, c.oid, c.relname, "
6410 						  "c.relacl, NULL as rrelacl, "
6411 						  "NULL AS initrelacl, NULL AS initrrelacl, "
6412 						  "c.relkind, "
6413 						  "c.relnamespace, "
6414 						  "(%s c.relowner) AS rolname, "
6415 						  "c.relchecks, (c.reltriggers <> 0) AS relhastriggers, "
6416 						  "c.relhasindex, c.relhasrules, c.relhasoids, "
6417 						  "'f'::bool AS relrowsecurity, "
6418 						  "'f'::bool AS relforcerowsecurity, "
6419 						  "c.relfrozenxid, 0 AS relminmxid, tc.oid AS toid, "
6420 						  "tc.relfrozenxid AS tfrozenxid, "
6421 						  "0 AS tminmxid, "
6422 						  "'p' AS relpersistence, 't' as relispopulated, "
6423 						  "'d' AS relreplident, c.relpages, "
6424 						  "NULL AS reloftype, "
6425 						  "d.refobjid AS owning_tab, "
6426 						  "d.refobjsubid AS owning_col, "
6427 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6428 						  "c.reloptions AS reloptions, "
6429 						  "NULL AS toast_reloptions, "
6430 						  "NULL AS changed_acl, "
6431 						  "NULL AS partkeydef, "
6432 						  "false AS ispartition, "
6433 						  "NULL AS partbound "
6434 						  "FROM pg_class c "
6435 						  "LEFT JOIN pg_depend d ON "
6436 						  "(c.relkind = '%c' AND "
6437 						  "d.classid = c.tableoid AND d.objid = c.oid AND "
6438 						  "d.objsubid = 0 AND "
6439 						  "d.refclassid = c.tableoid AND d.deptype = 'a') "
6440 						  "LEFT JOIN pg_class tc ON (c.reltoastrelid = tc.oid) "
6441 						  "WHERE c.relkind in ('%c', '%c', '%c', '%c') "
6442 						  "ORDER BY c.oid",
6443 						  username_subquery,
6444 						  RELKIND_SEQUENCE,
6445 						  RELKIND_RELATION, RELKIND_SEQUENCE,
6446 						  RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
6447 	}
6448 	else
6449 	{
6450 		/*
6451 		 * Left join to pick up dependency info linking sequences to their
6452 		 * owning column, if any
6453 		 */
6454 		appendPQExpBuffer(query,
6455 						  "SELECT c.tableoid, c.oid, relname, "
6456 						  "relacl, NULL as rrelacl, "
6457 						  "NULL AS initrelacl, NULL AS initrrelacl, "
6458 						  "relkind, relnamespace, "
6459 						  "(%s relowner) AS rolname, "
6460 						  "relchecks, (reltriggers <> 0) AS relhastriggers, "
6461 						  "relhasindex, relhasrules, relhasoids, "
6462 						  "'f'::bool AS relrowsecurity, "
6463 						  "'f'::bool AS relforcerowsecurity, "
6464 						  "0 AS relfrozenxid, 0 AS relminmxid,"
6465 						  "0 AS toid, "
6466 						  "0 AS tfrozenxid, 0 AS tminmxid,"
6467 						  "'p' AS relpersistence, 't' as relispopulated, "
6468 						  "'d' AS relreplident, relpages, "
6469 						  "NULL AS reloftype, "
6470 						  "d.refobjid AS owning_tab, "
6471 						  "d.refobjsubid AS owning_col, "
6472 						  "(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace, "
6473 						  "NULL AS reloptions, "
6474 						  "NULL AS toast_reloptions, "
6475 						  "NULL AS changed_acl, "
6476 						  "NULL AS partkeydef, "
6477 						  "false AS ispartition, "
6478 						  "NULL AS partbound "
6479 						  "FROM pg_class c "
6480 						  "LEFT JOIN pg_depend d ON "
6481 						  "(c.relkind = '%c' AND "
6482 						  "d.classid = c.tableoid AND d.objid = c.oid AND "
6483 						  "d.objsubid = 0 AND "
6484 						  "d.refclassid = c.tableoid AND d.deptype = 'i') "
6485 						  "WHERE relkind in ('%c', '%c', '%c', '%c') "
6486 						  "ORDER BY c.oid",
6487 						  username_subquery,
6488 						  RELKIND_SEQUENCE,
6489 						  RELKIND_RELATION, RELKIND_SEQUENCE,
6490 						  RELKIND_VIEW, RELKIND_COMPOSITE_TYPE);
6491 	}
6492 
6493 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6494 
6495 	ntups = PQntuples(res);
6496 
6497 	*numTables = ntups;
6498 
6499 	/*
6500 	 * Extract data from result and lock dumpable tables.  We do the locking
6501 	 * before anything else, to minimize the window wherein a table could
6502 	 * disappear under us.
6503 	 *
6504 	 * Note that we have to save info about all tables here, even when dumping
6505 	 * only one, because we don't yet know which tables might be inheritance
6506 	 * ancestors of the target table.
6507 	 */
6508 	tblinfo = (TableInfo *) pg_malloc0(ntups * sizeof(TableInfo));
6509 
6510 	i_reltableoid = PQfnumber(res, "tableoid");
6511 	i_reloid = PQfnumber(res, "oid");
6512 	i_relname = PQfnumber(res, "relname");
6513 	i_relnamespace = PQfnumber(res, "relnamespace");
6514 	i_relacl = PQfnumber(res, "relacl");
6515 	i_rrelacl = PQfnumber(res, "rrelacl");
6516 	i_initrelacl = PQfnumber(res, "initrelacl");
6517 	i_initrrelacl = PQfnumber(res, "initrrelacl");
6518 	i_relkind = PQfnumber(res, "relkind");
6519 	i_rolname = PQfnumber(res, "rolname");
6520 	i_relchecks = PQfnumber(res, "relchecks");
6521 	i_relhastriggers = PQfnumber(res, "relhastriggers");
6522 	i_relhasindex = PQfnumber(res, "relhasindex");
6523 	i_relhasrules = PQfnumber(res, "relhasrules");
6524 	i_relrowsec = PQfnumber(res, "relrowsecurity");
6525 	i_relforcerowsec = PQfnumber(res, "relforcerowsecurity");
6526 	i_relhasoids = PQfnumber(res, "relhasoids");
6527 	i_relfrozenxid = PQfnumber(res, "relfrozenxid");
6528 	i_relminmxid = PQfnumber(res, "relminmxid");
6529 	i_toastoid = PQfnumber(res, "toid");
6530 	i_toastfrozenxid = PQfnumber(res, "tfrozenxid");
6531 	i_toastminmxid = PQfnumber(res, "tminmxid");
6532 	i_relpersistence = PQfnumber(res, "relpersistence");
6533 	i_relispopulated = PQfnumber(res, "relispopulated");
6534 	i_relreplident = PQfnumber(res, "relreplident");
6535 	i_relpages = PQfnumber(res, "relpages");
6536 	i_owning_tab = PQfnumber(res, "owning_tab");
6537 	i_owning_col = PQfnumber(res, "owning_col");
6538 	i_reltablespace = PQfnumber(res, "reltablespace");
6539 	i_reloptions = PQfnumber(res, "reloptions");
6540 	i_checkoption = PQfnumber(res, "checkoption");
6541 	i_toastreloptions = PQfnumber(res, "toast_reloptions");
6542 	i_reloftype = PQfnumber(res, "reloftype");
6543 	i_is_identity_sequence = PQfnumber(res, "is_identity_sequence");
6544 	i_changed_acl = PQfnumber(res, "changed_acl");
6545 	i_partkeydef = PQfnumber(res, "partkeydef");
6546 	i_ispartition = PQfnumber(res, "ispartition");
6547 	i_partbound = PQfnumber(res, "partbound");
6548 
6549 	if (dopt->lockWaitTimeout)
6550 	{
6551 		/*
6552 		 * Arrange to fail instead of waiting forever for a table lock.
6553 		 *
6554 		 * NB: this coding assumes that the only queries issued within the
6555 		 * following loop are LOCK TABLEs; else the timeout may be undesirably
6556 		 * applied to other things too.
6557 		 */
6558 		resetPQExpBuffer(query);
6559 		appendPQExpBufferStr(query, "SET statement_timeout = ");
6560 		appendStringLiteralConn(query, dopt->lockWaitTimeout, GetConnection(fout));
6561 		ExecuteSqlStatement(fout, query->data);
6562 	}
6563 
6564 	for (i = 0; i < ntups; i++)
6565 	{
6566 		tblinfo[i].dobj.objType = DO_TABLE;
6567 		tblinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_reltableoid));
6568 		tblinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_reloid));
6569 		AssignDumpId(&tblinfo[i].dobj);
6570 		tblinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_relname));
6571 		tblinfo[i].dobj.namespace =
6572 			findNamespace(fout,
6573 						  atooid(PQgetvalue(res, i, i_relnamespace)));
6574 		tblinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
6575 		tblinfo[i].relacl = pg_strdup(PQgetvalue(res, i, i_relacl));
6576 		tblinfo[i].rrelacl = pg_strdup(PQgetvalue(res, i, i_rrelacl));
6577 		tblinfo[i].initrelacl = pg_strdup(PQgetvalue(res, i, i_initrelacl));
6578 		tblinfo[i].initrrelacl = pg_strdup(PQgetvalue(res, i, i_initrrelacl));
6579 		tblinfo[i].relkind = *(PQgetvalue(res, i, i_relkind));
6580 		tblinfo[i].relpersistence = *(PQgetvalue(res, i, i_relpersistence));
6581 		tblinfo[i].hasindex = (strcmp(PQgetvalue(res, i, i_relhasindex), "t") == 0);
6582 		tblinfo[i].hasrules = (strcmp(PQgetvalue(res, i, i_relhasrules), "t") == 0);
6583 		tblinfo[i].hastriggers = (strcmp(PQgetvalue(res, i, i_relhastriggers), "t") == 0);
6584 		tblinfo[i].rowsec = (strcmp(PQgetvalue(res, i, i_relrowsec), "t") == 0);
6585 		tblinfo[i].forcerowsec = (strcmp(PQgetvalue(res, i, i_relforcerowsec), "t") == 0);
6586 		tblinfo[i].hasoids = (strcmp(PQgetvalue(res, i, i_relhasoids), "t") == 0);
6587 		tblinfo[i].relispopulated = (strcmp(PQgetvalue(res, i, i_relispopulated), "t") == 0);
6588 		tblinfo[i].relreplident = *(PQgetvalue(res, i, i_relreplident));
6589 		tblinfo[i].relpages = atoi(PQgetvalue(res, i, i_relpages));
6590 		tblinfo[i].frozenxid = atooid(PQgetvalue(res, i, i_relfrozenxid));
6591 		tblinfo[i].minmxid = atooid(PQgetvalue(res, i, i_relminmxid));
6592 		tblinfo[i].toast_oid = atooid(PQgetvalue(res, i, i_toastoid));
6593 		tblinfo[i].toast_frozenxid = atooid(PQgetvalue(res, i, i_toastfrozenxid));
6594 		tblinfo[i].toast_minmxid = atooid(PQgetvalue(res, i, i_toastminmxid));
6595 		if (PQgetisnull(res, i, i_reloftype))
6596 			tblinfo[i].reloftype = NULL;
6597 		else
6598 			tblinfo[i].reloftype = pg_strdup(PQgetvalue(res, i, i_reloftype));
6599 		tblinfo[i].ncheck = atoi(PQgetvalue(res, i, i_relchecks));
6600 		if (PQgetisnull(res, i, i_owning_tab))
6601 		{
6602 			tblinfo[i].owning_tab = InvalidOid;
6603 			tblinfo[i].owning_col = 0;
6604 		}
6605 		else
6606 		{
6607 			tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
6608 			tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
6609 		}
6610 		tblinfo[i].reltablespace = pg_strdup(PQgetvalue(res, i, i_reltablespace));
6611 		tblinfo[i].reloptions = pg_strdup(PQgetvalue(res, i, i_reloptions));
6612 		if (i_checkoption == -1 || PQgetisnull(res, i, i_checkoption))
6613 			tblinfo[i].checkoption = NULL;
6614 		else
6615 			tblinfo[i].checkoption = pg_strdup(PQgetvalue(res, i, i_checkoption));
6616 		tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions));
6617 
6618 		/* other fields were zeroed above */
6619 
6620 		/*
6621 		 * Decide whether we want to dump this table.
6622 		 */
6623 		if (tblinfo[i].relkind == RELKIND_COMPOSITE_TYPE)
6624 			tblinfo[i].dobj.dump = DUMP_COMPONENT_NONE;
6625 		else
6626 			selectDumpableTable(&tblinfo[i], fout);
6627 
6628 		/*
6629 		 * If the table-level and all column-level ACLs for this table are
6630 		 * unchanged, then we don't need to worry about including the ACLs for
6631 		 * this table.  If any column-level ACLs have been changed, the
6632 		 * 'changed_acl' column from the query will indicate that.
6633 		 *
6634 		 * This can result in a significant performance improvement in cases
6635 		 * where we are only looking to dump out the ACL (eg: pg_catalog).
6636 		 */
6637 		if (PQgetisnull(res, i, i_relacl) && PQgetisnull(res, i, i_rrelacl) &&
6638 			PQgetisnull(res, i, i_initrelacl) &&
6639 			PQgetisnull(res, i, i_initrrelacl) &&
6640 			strcmp(PQgetvalue(res, i, i_changed_acl), "f") == 0)
6641 			tblinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
6642 
6643 		tblinfo[i].interesting = tblinfo[i].dobj.dump ? true : false;
6644 		tblinfo[i].dummy_view = false;	/* might get set during sort */
6645 		tblinfo[i].postponed_def = false;	/* might get set during sort */
6646 
6647 		tblinfo[i].is_identity_sequence = (i_is_identity_sequence >= 0 &&
6648 										   strcmp(PQgetvalue(res, i, i_is_identity_sequence), "t") == 0);
6649 
6650 		/* Partition key string or NULL */
6651 		tblinfo[i].partkeydef = pg_strdup(PQgetvalue(res, i, i_partkeydef));
6652 		tblinfo[i].ispartition = (strcmp(PQgetvalue(res, i, i_ispartition), "t") == 0);
6653 		tblinfo[i].partbound = pg_strdup(PQgetvalue(res, i, i_partbound));
6654 
6655 		/*
6656 		 * Read-lock target tables to make sure they aren't DROPPED or altered
6657 		 * in schema before we get around to dumping them.
6658 		 *
6659 		 * Note that we don't explicitly lock parents of the target tables; we
6660 		 * assume our lock on the child is enough to prevent schema
6661 		 * alterations to parent tables.
6662 		 *
6663 		 * NOTE: it'd be kinda nice to lock other relations too, not only
6664 		 * plain or partitioned tables, but the backend doesn't presently
6665 		 * allow that.
6666 		 *
6667 		 * We only need to lock the table for certain components; see
6668 		 * pg_dump.h
6669 		 */
6670 		if (tblinfo[i].dobj.dump &&
6671 			(tblinfo[i].relkind == RELKIND_RELATION ||
6672 			 tblinfo[i].relkind == RELKIND_PARTITIONED_TABLE) &&
6673 			(tblinfo[i].dobj.dump & DUMP_COMPONENTS_REQUIRING_LOCK))
6674 		{
6675 			resetPQExpBuffer(query);
6676 			appendPQExpBuffer(query,
6677 							  "LOCK TABLE %s IN ACCESS SHARE MODE",
6678 							  fmtQualifiedDumpable(&tblinfo[i]));
6679 			ExecuteSqlStatement(fout, query->data);
6680 		}
6681 
6682 		/* Emit notice if join for owner failed */
6683 		if (strlen(tblinfo[i].rolname) == 0)
6684 			write_msg(NULL, "WARNING: owner of table \"%s\" appears to be invalid\n",
6685 					  tblinfo[i].dobj.name);
6686 	}
6687 
6688 	if (dopt->lockWaitTimeout)
6689 	{
6690 		ExecuteSqlStatement(fout, "SET statement_timeout = 0");
6691 	}
6692 
6693 	PQclear(res);
6694 
6695 	destroyPQExpBuffer(query);
6696 
6697 	return tblinfo;
6698 }
6699 
6700 /*
6701  * getOwnedSeqs
6702  *	  identify owned sequences and mark them as dumpable if owning table is
6703  *
6704  * We used to do this in getTables(), but it's better to do it after the
6705  * index used by findTableByOid() has been set up.
6706  */
6707 void
getOwnedSeqs(Archive * fout,TableInfo tblinfo[],int numTables)6708 getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables)
6709 {
6710 	int			i;
6711 
6712 	/*
6713 	 * Force sequences that are "owned" by table columns to be dumped whenever
6714 	 * their owning table is being dumped.
6715 	 */
6716 	for (i = 0; i < numTables; i++)
6717 	{
6718 		TableInfo  *seqinfo = &tblinfo[i];
6719 		TableInfo  *owning_tab;
6720 
6721 		if (!OidIsValid(seqinfo->owning_tab))
6722 			continue;			/* not an owned sequence */
6723 
6724 		owning_tab = findTableByOid(seqinfo->owning_tab);
6725 		if (owning_tab == NULL)
6726 			exit_horribly(NULL, "failed sanity check, parent table with OID %u of sequence with OID %u not found\n",
6727 						  seqinfo->owning_tab, seqinfo->dobj.catId.oid);
6728 
6729 		/*
6730 		 * Only dump identity sequences if we're going to dump the table that
6731 		 * it belongs to.
6732 		 */
6733 		if (owning_tab->dobj.dump == DUMP_COMPONENT_NONE &&
6734 			seqinfo->is_identity_sequence)
6735 		{
6736 			seqinfo->dobj.dump = DUMP_COMPONENT_NONE;
6737 			continue;
6738 		}
6739 
6740 		/*
6741 		 * Otherwise we need to dump the components that are being dumped for
6742 		 * the table and any components which the sequence is explicitly
6743 		 * marked with.
6744 		 *
6745 		 * We can't simply use the set of components which are being dumped
6746 		 * for the table as the table might be in an extension (and only the
6747 		 * non-extension components, eg: ACLs if changed, security labels, and
6748 		 * policies, are being dumped) while the sequence is not (and
6749 		 * therefore the definition and other components should also be
6750 		 * dumped).
6751 		 *
6752 		 * If the sequence is part of the extension then it should be properly
6753 		 * marked by checkExtensionMembership() and this will be a no-op as
6754 		 * the table will be equivalently marked.
6755 		 */
6756 		seqinfo->dobj.dump = seqinfo->dobj.dump | owning_tab->dobj.dump;
6757 
6758 		if (seqinfo->dobj.dump != DUMP_COMPONENT_NONE)
6759 			seqinfo->interesting = true;
6760 	}
6761 }
6762 
6763 /*
6764  * getInherits
6765  *	  read all the inheritance information
6766  * from the system catalogs return them in the InhInfo* structure
6767  *
6768  * numInherits is set to the number of pairs read in
6769  */
6770 InhInfo *
getInherits(Archive * fout,int * numInherits)6771 getInherits(Archive *fout, int *numInherits)
6772 {
6773 	PGresult   *res;
6774 	int			ntups;
6775 	int			i;
6776 	PQExpBuffer query = createPQExpBuffer();
6777 	InhInfo    *inhinfo;
6778 
6779 	int			i_inhrelid;
6780 	int			i_inhparent;
6781 
6782 	/*
6783 	 * Find all the inheritance information, excluding implicit inheritance
6784 	 * via partitioning.  We handle that case using getPartitions(), because
6785 	 * we want more information about partitions than just the parent-child
6786 	 * relationship.
6787 	 */
6788 	appendPQExpBufferStr(query, "SELECT inhrelid, inhparent FROM pg_inherits");
6789 
6790 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
6791 
6792 	ntups = PQntuples(res);
6793 
6794 	*numInherits = ntups;
6795 
6796 	inhinfo = (InhInfo *) pg_malloc(ntups * sizeof(InhInfo));
6797 
6798 	i_inhrelid = PQfnumber(res, "inhrelid");
6799 	i_inhparent = PQfnumber(res, "inhparent");
6800 
6801 	for (i = 0; i < ntups; i++)
6802 	{
6803 		inhinfo[i].inhrelid = atooid(PQgetvalue(res, i, i_inhrelid));
6804 		inhinfo[i].inhparent = atooid(PQgetvalue(res, i, i_inhparent));
6805 	}
6806 
6807 	PQclear(res);
6808 
6809 	destroyPQExpBuffer(query);
6810 
6811 	return inhinfo;
6812 }
6813 
6814 /*
6815  * getIndexes
6816  *	  get information about every index on a dumpable table
6817  *
6818  * Note: index data is not returned directly to the caller, but it
6819  * does get entered into the DumpableObject tables.
6820  */
6821 void
getIndexes(Archive * fout,TableInfo tblinfo[],int numTables)6822 getIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
6823 {
6824 	int			i,
6825 				j;
6826 	PQExpBuffer query = createPQExpBuffer();
6827 	PGresult   *res;
6828 	IndxInfo   *indxinfo;
6829 	ConstraintInfo *constrinfo;
6830 	int			i_tableoid,
6831 				i_oid,
6832 				i_indexname,
6833 				i_parentidx,
6834 				i_indexdef,
6835 				i_indnkeyatts,
6836 				i_indnatts,
6837 				i_indkey,
6838 				i_indisclustered,
6839 				i_indisreplident,
6840 				i_contype,
6841 				i_conname,
6842 				i_condeferrable,
6843 				i_condeferred,
6844 				i_contableoid,
6845 				i_conoid,
6846 				i_condef,
6847 				i_tablespace,
6848 				i_indreloptions,
6849 				i_relpages,
6850 				i_indstatcols,
6851 				i_indstatvals;
6852 	int			ntups;
6853 
6854 	for (i = 0; i < numTables; i++)
6855 	{
6856 		TableInfo  *tbinfo = &tblinfo[i];
6857 
6858 		if (!tbinfo->hasindex)
6859 			continue;
6860 
6861 		/*
6862 		 * Ignore indexes of tables whose definitions are not to be dumped.
6863 		 *
6864 		 * We also need indexes on partitioned tables which have partitions to
6865 		 * be dumped, in order to dump the indexes on the partitions.
6866 		 */
6867 		if (!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION) &&
6868 			!tbinfo->interesting)
6869 			continue;
6870 
6871 		if (g_verbose)
6872 			write_msg(NULL, "reading indexes for table \"%s.%s\"\n",
6873 					  tbinfo->dobj.namespace->dobj.name,
6874 					  tbinfo->dobj.name);
6875 
6876 		/*
6877 		 * The point of the messy-looking outer join is to find a constraint
6878 		 * that is related by an internal dependency link to the index. If we
6879 		 * find one, create a CONSTRAINT entry linked to the INDEX entry.  We
6880 		 * assume an index won't have more than one internal dependency.
6881 		 *
6882 		 * As of 9.0 we don't need to look at pg_depend but can check for a
6883 		 * match to pg_constraint.conindid.  The check on conrelid is
6884 		 * redundant but useful because that column is indexed while conindid
6885 		 * is not.
6886 		 */
6887 		resetPQExpBuffer(query);
6888 		if (fout->remoteVersion >= 110000)
6889 		{
6890 			appendPQExpBuffer(query,
6891 							  "SELECT t.tableoid, t.oid, "
6892 							  "t.relname AS indexname, "
6893 							  "inh.inhparent AS parentidx, "
6894 							  "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6895 							  "i.indnkeyatts AS indnkeyatts, "
6896 							  "i.indnatts AS indnatts, "
6897 							  "i.indkey, i.indisclustered, "
6898 							  "i.indisreplident, t.relpages, "
6899 							  "c.contype, c.conname, "
6900 							  "c.condeferrable, c.condeferred, "
6901 							  "c.tableoid AS contableoid, "
6902 							  "c.oid AS conoid, "
6903 							  "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
6904 							  "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6905 							  "t.reloptions AS indreloptions, "
6906 							  "(SELECT pg_catalog.array_agg(attnum ORDER BY attnum) "
6907 							  "  FROM pg_catalog.pg_attribute "
6908 							  "  WHERE attrelid = i.indexrelid AND "
6909 							  "    attstattarget >= 0) AS indstatcols,"
6910 							  "(SELECT pg_catalog.array_agg(attstattarget ORDER BY attnum) "
6911 							  "  FROM pg_catalog.pg_attribute "
6912 							  "  WHERE attrelid = i.indexrelid AND "
6913 							  "    attstattarget >= 0) AS indstatvals "
6914 							  "FROM pg_catalog.pg_index i "
6915 							  "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6916 							  "JOIN pg_catalog.pg_class t2 ON (t2.oid = i.indrelid) "
6917 							  "LEFT JOIN pg_catalog.pg_constraint c "
6918 							  "ON (i.indrelid = c.conrelid AND "
6919 							  "i.indexrelid = c.conindid AND "
6920 							  "c.contype IN ('p','u','x')) "
6921 							  "LEFT JOIN pg_catalog.pg_inherits inh "
6922 							  "ON (inh.inhrelid = indexrelid) "
6923 							  "WHERE i.indrelid = '%u'::pg_catalog.oid "
6924 							  "AND (i.indisvalid OR t2.relkind = 'p') "
6925 							  "AND i.indisready "
6926 							  "ORDER BY indexname",
6927 							  tbinfo->dobj.catId.oid);
6928 		}
6929 		else if (fout->remoteVersion >= 90400)
6930 		{
6931 			/*
6932 			 * the test on indisready is necessary in 9.2, and harmless in
6933 			 * earlier/later versions
6934 			 */
6935 			appendPQExpBuffer(query,
6936 							  "SELECT t.tableoid, t.oid, "
6937 							  "t.relname AS indexname, "
6938 							  "0 AS parentidx, "
6939 							  "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6940 							  "i.indnatts AS indnkeyatts, "
6941 							  "i.indnatts AS indnatts, "
6942 							  "i.indkey, i.indisclustered, "
6943 							  "i.indisreplident, t.relpages, "
6944 							  "c.contype, c.conname, "
6945 							  "c.condeferrable, c.condeferred, "
6946 							  "c.tableoid AS contableoid, "
6947 							  "c.oid AS conoid, "
6948 							  "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
6949 							  "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6950 							  "t.reloptions AS indreloptions, "
6951 							  "'' AS indstatcols, "
6952 							  "'' AS indstatvals "
6953 							  "FROM pg_catalog.pg_index i "
6954 							  "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6955 							  "LEFT JOIN pg_catalog.pg_constraint c "
6956 							  "ON (i.indrelid = c.conrelid AND "
6957 							  "i.indexrelid = c.conindid AND "
6958 							  "c.contype IN ('p','u','x')) "
6959 							  "WHERE i.indrelid = '%u'::pg_catalog.oid "
6960 							  "AND i.indisvalid AND i.indisready "
6961 							  "ORDER BY indexname",
6962 							  tbinfo->dobj.catId.oid);
6963 		}
6964 		else if (fout->remoteVersion >= 90000)
6965 		{
6966 			/*
6967 			 * the test on indisready is necessary in 9.2, and harmless in
6968 			 * earlier/later versions
6969 			 */
6970 			appendPQExpBuffer(query,
6971 							  "SELECT t.tableoid, t.oid, "
6972 							  "t.relname AS indexname, "
6973 							  "0 AS parentidx, "
6974 							  "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
6975 							  "i.indnatts AS indnkeyatts, "
6976 							  "i.indnatts AS indnatts, "
6977 							  "i.indkey, i.indisclustered, "
6978 							  "false AS indisreplident, t.relpages, "
6979 							  "c.contype, c.conname, "
6980 							  "c.condeferrable, c.condeferred, "
6981 							  "c.tableoid AS contableoid, "
6982 							  "c.oid AS conoid, "
6983 							  "pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, "
6984 							  "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
6985 							  "t.reloptions AS indreloptions, "
6986 							  "'' AS indstatcols, "
6987 							  "'' AS indstatvals "
6988 							  "FROM pg_catalog.pg_index i "
6989 							  "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
6990 							  "LEFT JOIN pg_catalog.pg_constraint c "
6991 							  "ON (i.indrelid = c.conrelid AND "
6992 							  "i.indexrelid = c.conindid AND "
6993 							  "c.contype IN ('p','u','x')) "
6994 							  "WHERE i.indrelid = '%u'::pg_catalog.oid "
6995 							  "AND i.indisvalid AND i.indisready "
6996 							  "ORDER BY indexname",
6997 							  tbinfo->dobj.catId.oid);
6998 		}
6999 		else if (fout->remoteVersion >= 80200)
7000 		{
7001 			appendPQExpBuffer(query,
7002 							  "SELECT t.tableoid, t.oid, "
7003 							  "t.relname AS indexname, "
7004 							  "0 AS parentidx, "
7005 							  "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
7006 							  "i.indnatts AS indnkeyatts, "
7007 							  "i.indnatts AS indnatts, "
7008 							  "i.indkey, i.indisclustered, "
7009 							  "false AS indisreplident, t.relpages, "
7010 							  "c.contype, c.conname, "
7011 							  "c.condeferrable, c.condeferred, "
7012 							  "c.tableoid AS contableoid, "
7013 							  "c.oid AS conoid, "
7014 							  "null AS condef, "
7015 							  "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
7016 							  "t.reloptions AS indreloptions, "
7017 							  "'' AS indstatcols, "
7018 							  "'' AS indstatvals "
7019 							  "FROM pg_catalog.pg_index i "
7020 							  "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
7021 							  "LEFT JOIN pg_catalog.pg_depend d "
7022 							  "ON (d.classid = t.tableoid "
7023 							  "AND d.objid = t.oid "
7024 							  "AND d.deptype = 'i') "
7025 							  "LEFT JOIN pg_catalog.pg_constraint c "
7026 							  "ON (d.refclassid = c.tableoid "
7027 							  "AND d.refobjid = c.oid) "
7028 							  "WHERE i.indrelid = '%u'::pg_catalog.oid "
7029 							  "AND i.indisvalid "
7030 							  "ORDER BY indexname",
7031 							  tbinfo->dobj.catId.oid);
7032 		}
7033 		else
7034 		{
7035 			appendPQExpBuffer(query,
7036 							  "SELECT t.tableoid, t.oid, "
7037 							  "t.relname AS indexname, "
7038 							  "0 AS parentidx, "
7039 							  "pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, "
7040 							  "t.relnatts AS indnkeyatts, "
7041 							  "t.relnatts AS indnatts, "
7042 							  "i.indkey, i.indisclustered, "
7043 							  "false AS indisreplident, t.relpages, "
7044 							  "c.contype, c.conname, "
7045 							  "c.condeferrable, c.condeferred, "
7046 							  "c.tableoid AS contableoid, "
7047 							  "c.oid AS conoid, "
7048 							  "null AS condef, "
7049 							  "(SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, "
7050 							  "null AS indreloptions, "
7051 							  "'' AS indstatcols, "
7052 							  "'' AS indstatvals "
7053 							  "FROM pg_catalog.pg_index i "
7054 							  "JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) "
7055 							  "LEFT JOIN pg_catalog.pg_depend d "
7056 							  "ON (d.classid = t.tableoid "
7057 							  "AND d.objid = t.oid "
7058 							  "AND d.deptype = 'i') "
7059 							  "LEFT JOIN pg_catalog.pg_constraint c "
7060 							  "ON (d.refclassid = c.tableoid "
7061 							  "AND d.refobjid = c.oid) "
7062 							  "WHERE i.indrelid = '%u'::pg_catalog.oid "
7063 							  "ORDER BY indexname",
7064 							  tbinfo->dobj.catId.oid);
7065 		}
7066 
7067 		res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7068 
7069 		ntups = PQntuples(res);
7070 
7071 		i_tableoid = PQfnumber(res, "tableoid");
7072 		i_oid = PQfnumber(res, "oid");
7073 		i_indexname = PQfnumber(res, "indexname");
7074 		i_parentidx = PQfnumber(res, "parentidx");
7075 		i_indexdef = PQfnumber(res, "indexdef");
7076 		i_indnkeyatts = PQfnumber(res, "indnkeyatts");
7077 		i_indnatts = PQfnumber(res, "indnatts");
7078 		i_indkey = PQfnumber(res, "indkey");
7079 		i_indisclustered = PQfnumber(res, "indisclustered");
7080 		i_indisreplident = PQfnumber(res, "indisreplident");
7081 		i_relpages = PQfnumber(res, "relpages");
7082 		i_contype = PQfnumber(res, "contype");
7083 		i_conname = PQfnumber(res, "conname");
7084 		i_condeferrable = PQfnumber(res, "condeferrable");
7085 		i_condeferred = PQfnumber(res, "condeferred");
7086 		i_contableoid = PQfnumber(res, "contableoid");
7087 		i_conoid = PQfnumber(res, "conoid");
7088 		i_condef = PQfnumber(res, "condef");
7089 		i_tablespace = PQfnumber(res, "tablespace");
7090 		i_indreloptions = PQfnumber(res, "indreloptions");
7091 		i_indstatcols = PQfnumber(res, "indstatcols");
7092 		i_indstatvals = PQfnumber(res, "indstatvals");
7093 
7094 		tbinfo->indexes = indxinfo =
7095 			(IndxInfo *) pg_malloc(ntups * sizeof(IndxInfo));
7096 		constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
7097 		tbinfo->numIndexes = ntups;
7098 
7099 		for (j = 0; j < ntups; j++)
7100 		{
7101 			char		contype;
7102 
7103 			indxinfo[j].dobj.objType = DO_INDEX;
7104 			indxinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
7105 			indxinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
7106 			AssignDumpId(&indxinfo[j].dobj);
7107 			indxinfo[j].dobj.dump = tbinfo->dobj.dump;
7108 			indxinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_indexname));
7109 			indxinfo[j].dobj.namespace = tbinfo->dobj.namespace;
7110 			indxinfo[j].indextable = tbinfo;
7111 			indxinfo[j].indexdef = pg_strdup(PQgetvalue(res, j, i_indexdef));
7112 			indxinfo[j].indnkeyattrs = atoi(PQgetvalue(res, j, i_indnkeyatts));
7113 			indxinfo[j].indnattrs = atoi(PQgetvalue(res, j, i_indnatts));
7114 			indxinfo[j].tablespace = pg_strdup(PQgetvalue(res, j, i_tablespace));
7115 			indxinfo[j].indreloptions = pg_strdup(PQgetvalue(res, j, i_indreloptions));
7116 			indxinfo[j].indstatcols = pg_strdup(PQgetvalue(res, j, i_indstatcols));
7117 			indxinfo[j].indstatvals = pg_strdup(PQgetvalue(res, j, i_indstatvals));
7118 			indxinfo[j].indkeys = (Oid *) pg_malloc(indxinfo[j].indnattrs * sizeof(Oid));
7119 			parseOidArray(PQgetvalue(res, j, i_indkey),
7120 						  indxinfo[j].indkeys, indxinfo[j].indnattrs);
7121 			indxinfo[j].indisclustered = (PQgetvalue(res, j, i_indisclustered)[0] == 't');
7122 			indxinfo[j].indisreplident = (PQgetvalue(res, j, i_indisreplident)[0] == 't');
7123 			indxinfo[j].parentidx = atooid(PQgetvalue(res, j, i_parentidx));
7124 			indxinfo[j].relpages = atoi(PQgetvalue(res, j, i_relpages));
7125 			contype = *(PQgetvalue(res, j, i_contype));
7126 
7127 			if (contype == 'p' || contype == 'u' || contype == 'x')
7128 			{
7129 				/*
7130 				 * If we found a constraint matching the index, create an
7131 				 * entry for it.
7132 				 */
7133 				constrinfo[j].dobj.objType = DO_CONSTRAINT;
7134 				constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
7135 				constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
7136 				AssignDumpId(&constrinfo[j].dobj);
7137 				constrinfo[j].dobj.dump = tbinfo->dobj.dump;
7138 				constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
7139 				constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
7140 				constrinfo[j].contable = tbinfo;
7141 				constrinfo[j].condomain = NULL;
7142 				constrinfo[j].contype = contype;
7143 				if (contype == 'x')
7144 					constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
7145 				else
7146 					constrinfo[j].condef = NULL;
7147 				constrinfo[j].confrelid = InvalidOid;
7148 				constrinfo[j].conindex = indxinfo[j].dobj.dumpId;
7149 				constrinfo[j].condeferrable = *(PQgetvalue(res, j, i_condeferrable)) == 't';
7150 				constrinfo[j].condeferred = *(PQgetvalue(res, j, i_condeferred)) == 't';
7151 				constrinfo[j].conislocal = true;
7152 				constrinfo[j].separate = true;
7153 
7154 				indxinfo[j].indexconstraint = constrinfo[j].dobj.dumpId;
7155 			}
7156 			else
7157 			{
7158 				/* Plain secondary index */
7159 				indxinfo[j].indexconstraint = 0;
7160 			}
7161 		}
7162 
7163 		PQclear(res);
7164 	}
7165 
7166 	destroyPQExpBuffer(query);
7167 }
7168 
7169 /*
7170  * getExtendedStatistics
7171  *	  get information about extended-statistics objects.
7172  *
7173  * Note: extended statistics data is not returned directly to the caller, but
7174  * it does get entered into the DumpableObject tables.
7175  */
7176 void
getExtendedStatistics(Archive * fout)7177 getExtendedStatistics(Archive *fout)
7178 {
7179 	PQExpBuffer query;
7180 	PGresult   *res;
7181 	StatsExtInfo *statsextinfo;
7182 	int			ntups;
7183 	int			i_tableoid;
7184 	int			i_oid;
7185 	int			i_stxname;
7186 	int			i_stxnamespace;
7187 	int			i_rolname;
7188 	int			i;
7189 
7190 	/* Extended statistics were new in v10 */
7191 	if (fout->remoteVersion < 100000)
7192 		return;
7193 
7194 	query = createPQExpBuffer();
7195 
7196 	appendPQExpBuffer(query, "SELECT tableoid, oid, stxname, "
7197 					  "stxnamespace, (%s stxowner) AS rolname "
7198 					  "FROM pg_catalog.pg_statistic_ext",
7199 					  username_subquery);
7200 
7201 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7202 
7203 	ntups = PQntuples(res);
7204 
7205 	i_tableoid = PQfnumber(res, "tableoid");
7206 	i_oid = PQfnumber(res, "oid");
7207 	i_stxname = PQfnumber(res, "stxname");
7208 	i_stxnamespace = PQfnumber(res, "stxnamespace");
7209 	i_rolname = PQfnumber(res, "rolname");
7210 
7211 	statsextinfo = (StatsExtInfo *) pg_malloc(ntups * sizeof(StatsExtInfo));
7212 
7213 	for (i = 0; i < ntups; i++)
7214 	{
7215 		statsextinfo[i].dobj.objType = DO_STATSEXT;
7216 		statsextinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7217 		statsextinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7218 		AssignDumpId(&statsextinfo[i].dobj);
7219 		statsextinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_stxname));
7220 		statsextinfo[i].dobj.namespace =
7221 			findNamespace(fout,
7222 						  atooid(PQgetvalue(res, i, i_stxnamespace)));
7223 		statsextinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
7224 
7225 		/* Decide whether we want to dump it */
7226 		selectDumpableObject(&(statsextinfo[i].dobj), fout);
7227 
7228 		/* Stats objects do not currently have ACLs. */
7229 		statsextinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
7230 	}
7231 
7232 	PQclear(res);
7233 	destroyPQExpBuffer(query);
7234 }
7235 
7236 /*
7237  * getConstraints
7238  *
7239  * Get info about constraints on dumpable tables.
7240  *
7241  * Currently handles foreign keys only.
7242  * Unique and primary key constraints are handled with indexes,
7243  * while check constraints are processed in getTableAttrs().
7244  */
7245 void
getConstraints(Archive * fout,TableInfo tblinfo[],int numTables)7246 getConstraints(Archive *fout, TableInfo tblinfo[], int numTables)
7247 {
7248 	int			i,
7249 				j;
7250 	ConstraintInfo *constrinfo;
7251 	PQExpBuffer query;
7252 	PGresult   *res;
7253 	int			i_contableoid,
7254 				i_conoid,
7255 				i_conname,
7256 				i_confrelid,
7257 				i_condef;
7258 	int			ntups;
7259 
7260 	query = createPQExpBuffer();
7261 
7262 	for (i = 0; i < numTables; i++)
7263 	{
7264 		TableInfo  *tbinfo = &tblinfo[i];
7265 
7266 		/*
7267 		 * For partitioned tables, foreign keys have no triggers so they must
7268 		 * be included anyway in case some foreign keys are defined.
7269 		 */
7270 		if ((!tbinfo->hastriggers &&
7271 			 tbinfo->relkind != RELKIND_PARTITIONED_TABLE) ||
7272 			!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
7273 			continue;
7274 
7275 		if (g_verbose)
7276 			write_msg(NULL, "reading foreign key constraints for table \"%s.%s\"\n",
7277 					  tbinfo->dobj.namespace->dobj.name,
7278 					  tbinfo->dobj.name);
7279 
7280 		resetPQExpBuffer(query);
7281 		if (fout->remoteVersion >= 110000)
7282 			appendPQExpBuffer(query,
7283 							  "SELECT tableoid, oid, conname, confrelid, "
7284 							  "pg_catalog.pg_get_constraintdef(oid) AS condef "
7285 							  "FROM pg_catalog.pg_constraint "
7286 							  "WHERE conrelid = '%u'::pg_catalog.oid "
7287 							  "AND conparentid = 0 "
7288 							  "AND contype = 'f'",
7289 							  tbinfo->dobj.catId.oid);
7290 		else
7291 			appendPQExpBuffer(query,
7292 							  "SELECT tableoid, oid, conname, confrelid, "
7293 							  "pg_catalog.pg_get_constraintdef(oid) AS condef "
7294 							  "FROM pg_catalog.pg_constraint "
7295 							  "WHERE conrelid = '%u'::pg_catalog.oid "
7296 							  "AND contype = 'f'",
7297 							  tbinfo->dobj.catId.oid);
7298 		res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7299 
7300 		ntups = PQntuples(res);
7301 
7302 		i_contableoid = PQfnumber(res, "tableoid");
7303 		i_conoid = PQfnumber(res, "oid");
7304 		i_conname = PQfnumber(res, "conname");
7305 		i_confrelid = PQfnumber(res, "confrelid");
7306 		i_condef = PQfnumber(res, "condef");
7307 
7308 		constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
7309 
7310 		for (j = 0; j < ntups; j++)
7311 		{
7312 			constrinfo[j].dobj.objType = DO_FK_CONSTRAINT;
7313 			constrinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_contableoid));
7314 			constrinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_conoid));
7315 			AssignDumpId(&constrinfo[j].dobj);
7316 			constrinfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_conname));
7317 			constrinfo[j].dobj.namespace = tbinfo->dobj.namespace;
7318 			constrinfo[j].contable = tbinfo;
7319 			constrinfo[j].condomain = NULL;
7320 			constrinfo[j].contype = 'f';
7321 			constrinfo[j].condef = pg_strdup(PQgetvalue(res, j, i_condef));
7322 			constrinfo[j].confrelid = atooid(PQgetvalue(res, j, i_confrelid));
7323 			constrinfo[j].conindex = 0;
7324 			constrinfo[j].condeferrable = false;
7325 			constrinfo[j].condeferred = false;
7326 			constrinfo[j].conislocal = true;
7327 			constrinfo[j].separate = true;
7328 		}
7329 
7330 		PQclear(res);
7331 	}
7332 
7333 	destroyPQExpBuffer(query);
7334 }
7335 
7336 /*
7337  * getDomainConstraints
7338  *
7339  * Get info about constraints on a domain.
7340  */
7341 static void
getDomainConstraints(Archive * fout,TypeInfo * tyinfo)7342 getDomainConstraints(Archive *fout, TypeInfo *tyinfo)
7343 {
7344 	int			i;
7345 	ConstraintInfo *constrinfo;
7346 	PQExpBuffer query;
7347 	PGresult   *res;
7348 	int			i_tableoid,
7349 				i_oid,
7350 				i_conname,
7351 				i_consrc;
7352 	int			ntups;
7353 
7354 	query = createPQExpBuffer();
7355 
7356 	if (fout->remoteVersion >= 90100)
7357 		appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
7358 						  "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
7359 						  "convalidated "
7360 						  "FROM pg_catalog.pg_constraint "
7361 						  "WHERE contypid = '%u'::pg_catalog.oid "
7362 						  "ORDER BY conname",
7363 						  tyinfo->dobj.catId.oid);
7364 
7365 	else
7366 		appendPQExpBuffer(query, "SELECT tableoid, oid, conname, "
7367 						  "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
7368 						  "true as convalidated "
7369 						  "FROM pg_catalog.pg_constraint "
7370 						  "WHERE contypid = '%u'::pg_catalog.oid "
7371 						  "ORDER BY conname",
7372 						  tyinfo->dobj.catId.oid);
7373 
7374 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7375 
7376 	ntups = PQntuples(res);
7377 
7378 	i_tableoid = PQfnumber(res, "tableoid");
7379 	i_oid = PQfnumber(res, "oid");
7380 	i_conname = PQfnumber(res, "conname");
7381 	i_consrc = PQfnumber(res, "consrc");
7382 
7383 	constrinfo = (ConstraintInfo *) pg_malloc(ntups * sizeof(ConstraintInfo));
7384 
7385 	tyinfo->nDomChecks = ntups;
7386 	tyinfo->domChecks = constrinfo;
7387 
7388 	for (i = 0; i < ntups; i++)
7389 	{
7390 		bool		validated = PQgetvalue(res, i, 4)[0] == 't';
7391 
7392 		constrinfo[i].dobj.objType = DO_CONSTRAINT;
7393 		constrinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7394 		constrinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7395 		AssignDumpId(&constrinfo[i].dobj);
7396 		constrinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_conname));
7397 		constrinfo[i].dobj.namespace = tyinfo->dobj.namespace;
7398 		constrinfo[i].contable = NULL;
7399 		constrinfo[i].condomain = tyinfo;
7400 		constrinfo[i].contype = 'c';
7401 		constrinfo[i].condef = pg_strdup(PQgetvalue(res, i, i_consrc));
7402 		constrinfo[i].confrelid = InvalidOid;
7403 		constrinfo[i].conindex = 0;
7404 		constrinfo[i].condeferrable = false;
7405 		constrinfo[i].condeferred = false;
7406 		constrinfo[i].conislocal = true;
7407 
7408 		constrinfo[i].separate = !validated;
7409 
7410 		/*
7411 		 * Make the domain depend on the constraint, ensuring it won't be
7412 		 * output till any constraint dependencies are OK.  If the constraint
7413 		 * has not been validated, it's going to be dumped after the domain
7414 		 * anyway, so this doesn't matter.
7415 		 */
7416 		if (validated)
7417 			addObjectDependency(&tyinfo->dobj,
7418 								constrinfo[i].dobj.dumpId);
7419 	}
7420 
7421 	PQclear(res);
7422 
7423 	destroyPQExpBuffer(query);
7424 }
7425 
7426 /*
7427  * getRules
7428  *	  get basic information about every rule in the system
7429  *
7430  * numRules is set to the number of rules read in
7431  */
7432 RuleInfo *
getRules(Archive * fout,int * numRules)7433 getRules(Archive *fout, int *numRules)
7434 {
7435 	PGresult   *res;
7436 	int			ntups;
7437 	int			i;
7438 	PQExpBuffer query = createPQExpBuffer();
7439 	RuleInfo   *ruleinfo;
7440 	int			i_tableoid;
7441 	int			i_oid;
7442 	int			i_rulename;
7443 	int			i_ruletable;
7444 	int			i_ev_type;
7445 	int			i_is_instead;
7446 	int			i_ev_enabled;
7447 
7448 	if (fout->remoteVersion >= 80300)
7449 	{
7450 		appendPQExpBufferStr(query, "SELECT "
7451 							 "tableoid, oid, rulename, "
7452 							 "ev_class AS ruletable, ev_type, is_instead, "
7453 							 "ev_enabled "
7454 							 "FROM pg_rewrite "
7455 							 "ORDER BY oid");
7456 	}
7457 	else
7458 	{
7459 		appendPQExpBufferStr(query, "SELECT "
7460 							 "tableoid, oid, rulename, "
7461 							 "ev_class AS ruletable, ev_type, is_instead, "
7462 							 "'O'::char AS ev_enabled "
7463 							 "FROM pg_rewrite "
7464 							 "ORDER BY oid");
7465 	}
7466 
7467 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7468 
7469 	ntups = PQntuples(res);
7470 
7471 	*numRules = ntups;
7472 
7473 	ruleinfo = (RuleInfo *) pg_malloc(ntups * sizeof(RuleInfo));
7474 
7475 	i_tableoid = PQfnumber(res, "tableoid");
7476 	i_oid = PQfnumber(res, "oid");
7477 	i_rulename = PQfnumber(res, "rulename");
7478 	i_ruletable = PQfnumber(res, "ruletable");
7479 	i_ev_type = PQfnumber(res, "ev_type");
7480 	i_is_instead = PQfnumber(res, "is_instead");
7481 	i_ev_enabled = PQfnumber(res, "ev_enabled");
7482 
7483 	for (i = 0; i < ntups; i++)
7484 	{
7485 		Oid			ruletableoid;
7486 
7487 		ruleinfo[i].dobj.objType = DO_RULE;
7488 		ruleinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7489 		ruleinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7490 		AssignDumpId(&ruleinfo[i].dobj);
7491 		ruleinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_rulename));
7492 		ruletableoid = atooid(PQgetvalue(res, i, i_ruletable));
7493 		ruleinfo[i].ruletable = findTableByOid(ruletableoid);
7494 		if (ruleinfo[i].ruletable == NULL)
7495 			exit_horribly(NULL, "failed sanity check, parent table with OID %u of pg_rewrite entry with OID %u not found\n",
7496 						  ruletableoid, ruleinfo[i].dobj.catId.oid);
7497 		ruleinfo[i].dobj.namespace = ruleinfo[i].ruletable->dobj.namespace;
7498 		ruleinfo[i].dobj.dump = ruleinfo[i].ruletable->dobj.dump;
7499 		ruleinfo[i].ev_type = *(PQgetvalue(res, i, i_ev_type));
7500 		ruleinfo[i].is_instead = *(PQgetvalue(res, i, i_is_instead)) == 't';
7501 		ruleinfo[i].ev_enabled = *(PQgetvalue(res, i, i_ev_enabled));
7502 		if (ruleinfo[i].ruletable)
7503 		{
7504 			/*
7505 			 * If the table is a view or materialized view, force its ON
7506 			 * SELECT rule to be sorted before the view itself --- this
7507 			 * ensures that any dependencies for the rule affect the table's
7508 			 * positioning. Other rules are forced to appear after their
7509 			 * table.
7510 			 */
7511 			if ((ruleinfo[i].ruletable->relkind == RELKIND_VIEW ||
7512 				 ruleinfo[i].ruletable->relkind == RELKIND_MATVIEW) &&
7513 				ruleinfo[i].ev_type == '1' && ruleinfo[i].is_instead)
7514 			{
7515 				addObjectDependency(&ruleinfo[i].ruletable->dobj,
7516 									ruleinfo[i].dobj.dumpId);
7517 				/* We'll merge the rule into CREATE VIEW, if possible */
7518 				ruleinfo[i].separate = false;
7519 			}
7520 			else
7521 			{
7522 				addObjectDependency(&ruleinfo[i].dobj,
7523 									ruleinfo[i].ruletable->dobj.dumpId);
7524 				ruleinfo[i].separate = true;
7525 			}
7526 		}
7527 		else
7528 			ruleinfo[i].separate = true;
7529 	}
7530 
7531 	PQclear(res);
7532 
7533 	destroyPQExpBuffer(query);
7534 
7535 	return ruleinfo;
7536 }
7537 
7538 /*
7539  * getTriggers
7540  *	  get information about every trigger on a dumpable table
7541  *
7542  * Note: trigger data is not returned directly to the caller, but it
7543  * does get entered into the DumpableObject tables.
7544  */
7545 void
getTriggers(Archive * fout,TableInfo tblinfo[],int numTables)7546 getTriggers(Archive *fout, TableInfo tblinfo[], int numTables)
7547 {
7548 	int			i,
7549 				j;
7550 	PQExpBuffer query = createPQExpBuffer();
7551 	PGresult   *res;
7552 	TriggerInfo *tginfo;
7553 	int			i_tableoid,
7554 				i_oid,
7555 				i_tgname,
7556 				i_tgfname,
7557 				i_tgtype,
7558 				i_tgnargs,
7559 				i_tgargs,
7560 				i_tgisconstraint,
7561 				i_tgconstrname,
7562 				i_tgconstrrelid,
7563 				i_tgconstrrelname,
7564 				i_tgenabled,
7565 				i_tgisinternal,
7566 				i_tgdeferrable,
7567 				i_tginitdeferred,
7568 				i_tgdef;
7569 	int			ntups;
7570 
7571 	for (i = 0; i < numTables; i++)
7572 	{
7573 		TableInfo  *tbinfo = &tblinfo[i];
7574 
7575 		if (!tbinfo->hastriggers ||
7576 			!(tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION))
7577 			continue;
7578 
7579 		if (g_verbose)
7580 			write_msg(NULL, "reading triggers for table \"%s.%s\"\n",
7581 					  tbinfo->dobj.namespace->dobj.name,
7582 					  tbinfo->dobj.name);
7583 
7584 		resetPQExpBuffer(query);
7585 		if (fout->remoteVersion >= 130000)
7586 		{
7587 			/*
7588 			 * NB: think not to use pretty=true in pg_get_triggerdef.  It
7589 			 * could result in non-forward-compatible dumps of WHEN clauses
7590 			 * due to under-parenthesization.
7591 			 *
7592 			 * NB: We need to see tgisinternal triggers in partitions, in case
7593 			 * the tgenabled flag has been changed from the parent.
7594 			 */
7595 			appendPQExpBuffer(query,
7596 							  "SELECT t.tgname, "
7597 							  "t.tgfoid::pg_catalog.regproc AS tgfname, "
7598 							  "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
7599 							  "t.tgenabled, t.tableoid, t.oid, t.tgisinternal "
7600 							  "FROM pg_catalog.pg_trigger t "
7601 							  "LEFT JOIN pg_catalog.pg_trigger u ON u.oid = t.tgparentid "
7602 							  "WHERE t.tgrelid = '%u'::pg_catalog.oid "
7603 							  "AND (NOT t.tgisinternal OR t.tgenabled != u.tgenabled)",
7604 							  tbinfo->dobj.catId.oid);
7605 		}
7606 		else if (fout->remoteVersion >= 110000)
7607 		{
7608 			/*
7609 			 * NB: We need to see tgisinternal triggers in partitions, in case
7610 			 * the tgenabled flag has been changed from the parent. No
7611 			 * tgparentid in version 11-12, so we have to match them via
7612 			 * pg_depend.
7613 			 *
7614 			 * See above about pretty=true in pg_get_triggerdef.
7615 			 */
7616 			appendPQExpBuffer(query,
7617 							  "SELECT t.tgname, "
7618 							  "t.tgfoid::pg_catalog.regproc AS tgfname, "
7619 							  "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
7620 							  "t.tgenabled, t.tableoid, t.oid, t.tgisinternal "
7621 							  "FROM pg_catalog.pg_trigger t "
7622 							  "LEFT JOIN pg_catalog.pg_depend AS d ON "
7623 							  " d.classid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "
7624 							  " d.refclassid = 'pg_catalog.pg_trigger'::pg_catalog.regclass AND "
7625 							  " d.objid = t.oid "
7626 							  "LEFT JOIN pg_catalog.pg_trigger AS pt ON pt.oid = refobjid "
7627 							  "WHERE t.tgrelid = '%u'::pg_catalog.oid "
7628 							  "AND (NOT t.tgisinternal%s)",
7629 							  tbinfo->dobj.catId.oid,
7630 							  tbinfo->ispartition ?
7631 							  " OR t.tgenabled != pt.tgenabled" : "");
7632 		}
7633 		else if (fout->remoteVersion >= 90000)
7634 		{
7635 			/* See above about pretty=true in pg_get_triggerdef */
7636 			appendPQExpBuffer(query,
7637 							  "SELECT t.tgname, "
7638 							  "t.tgfoid::pg_catalog.regproc AS tgfname, "
7639 							  "pg_catalog.pg_get_triggerdef(t.oid, false) AS tgdef, "
7640 							  "t.tgenabled, false as tgisinternal, "
7641 							  "t.tableoid, t.oid "
7642 							  "FROM pg_catalog.pg_trigger t "
7643 							  "WHERE tgrelid = '%u'::pg_catalog.oid "
7644 							  "AND NOT tgisinternal",
7645 							  tbinfo->dobj.catId.oid);
7646 		}
7647 		else if (fout->remoteVersion >= 80300)
7648 		{
7649 			/*
7650 			 * We ignore triggers that are tied to a foreign-key constraint
7651 			 */
7652 			appendPQExpBuffer(query,
7653 							  "SELECT tgname, "
7654 							  "tgfoid::pg_catalog.regproc AS tgfname, "
7655 							  "tgtype, tgnargs, tgargs, tgenabled, "
7656 							  "false as tgisinternal, "
7657 							  "tgisconstraint, tgconstrname, tgdeferrable, "
7658 							  "tgconstrrelid, tginitdeferred, tableoid, oid, "
7659 							  "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
7660 							  "FROM pg_catalog.pg_trigger t "
7661 							  "WHERE tgrelid = '%u'::pg_catalog.oid "
7662 							  "AND tgconstraint = 0",
7663 							  tbinfo->dobj.catId.oid);
7664 		}
7665 		else
7666 		{
7667 			/*
7668 			 * We ignore triggers that are tied to a foreign-key constraint,
7669 			 * but in these versions we have to grovel through pg_constraint
7670 			 * to find out
7671 			 */
7672 			appendPQExpBuffer(query,
7673 							  "SELECT tgname, "
7674 							  "tgfoid::pg_catalog.regproc AS tgfname, "
7675 							  "tgtype, tgnargs, tgargs, tgenabled, "
7676 							  "false as tgisinternal, "
7677 							  "tgisconstraint, tgconstrname, tgdeferrable, "
7678 							  "tgconstrrelid, tginitdeferred, tableoid, oid, "
7679 							  "tgconstrrelid::pg_catalog.regclass AS tgconstrrelname "
7680 							  "FROM pg_catalog.pg_trigger t "
7681 							  "WHERE tgrelid = '%u'::pg_catalog.oid "
7682 							  "AND (NOT tgisconstraint "
7683 							  " OR NOT EXISTS"
7684 							  "  (SELECT 1 FROM pg_catalog.pg_depend d "
7685 							  "   JOIN pg_catalog.pg_constraint c ON (d.refclassid = c.tableoid AND d.refobjid = c.oid) "
7686 							  "   WHERE d.classid = t.tableoid AND d.objid = t.oid AND d.deptype = 'i' AND c.contype = 'f'))",
7687 							  tbinfo->dobj.catId.oid);
7688 		}
7689 
7690 		res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7691 
7692 		ntups = PQntuples(res);
7693 
7694 		i_tableoid = PQfnumber(res, "tableoid");
7695 		i_oid = PQfnumber(res, "oid");
7696 		i_tgname = PQfnumber(res, "tgname");
7697 		i_tgfname = PQfnumber(res, "tgfname");
7698 		i_tgtype = PQfnumber(res, "tgtype");
7699 		i_tgnargs = PQfnumber(res, "tgnargs");
7700 		i_tgargs = PQfnumber(res, "tgargs");
7701 		i_tgisconstraint = PQfnumber(res, "tgisconstraint");
7702 		i_tgconstrname = PQfnumber(res, "tgconstrname");
7703 		i_tgconstrrelid = PQfnumber(res, "tgconstrrelid");
7704 		i_tgconstrrelname = PQfnumber(res, "tgconstrrelname");
7705 		i_tgenabled = PQfnumber(res, "tgenabled");
7706 		i_tgisinternal = PQfnumber(res, "tgisinternal");
7707 		i_tgdeferrable = PQfnumber(res, "tgdeferrable");
7708 		i_tginitdeferred = PQfnumber(res, "tginitdeferred");
7709 		i_tgdef = PQfnumber(res, "tgdef");
7710 
7711 		tginfo = (TriggerInfo *) pg_malloc(ntups * sizeof(TriggerInfo));
7712 
7713 		tbinfo->numTriggers = ntups;
7714 		tbinfo->triggers = tginfo;
7715 
7716 		for (j = 0; j < ntups; j++)
7717 		{
7718 			tginfo[j].dobj.objType = DO_TRIGGER;
7719 			tginfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid));
7720 			tginfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid));
7721 			AssignDumpId(&tginfo[j].dobj);
7722 			tginfo[j].dobj.name = pg_strdup(PQgetvalue(res, j, i_tgname));
7723 			tginfo[j].dobj.namespace = tbinfo->dobj.namespace;
7724 			tginfo[j].tgtable = tbinfo;
7725 			tginfo[j].tgenabled = *(PQgetvalue(res, j, i_tgenabled));
7726 			tginfo[j].tgisinternal = *(PQgetvalue(res, j, i_tgisinternal)) == 't';
7727 			if (i_tgdef >= 0)
7728 			{
7729 				tginfo[j].tgdef = pg_strdup(PQgetvalue(res, j, i_tgdef));
7730 
7731 				/* remaining fields are not valid if we have tgdef */
7732 				tginfo[j].tgfname = NULL;
7733 				tginfo[j].tgtype = 0;
7734 				tginfo[j].tgnargs = 0;
7735 				tginfo[j].tgargs = NULL;
7736 				tginfo[j].tgisconstraint = false;
7737 				tginfo[j].tgdeferrable = false;
7738 				tginfo[j].tginitdeferred = false;
7739 				tginfo[j].tgconstrname = NULL;
7740 				tginfo[j].tgconstrrelid = InvalidOid;
7741 				tginfo[j].tgconstrrelname = NULL;
7742 			}
7743 			else
7744 			{
7745 				tginfo[j].tgdef = NULL;
7746 
7747 				tginfo[j].tgfname = pg_strdup(PQgetvalue(res, j, i_tgfname));
7748 				tginfo[j].tgtype = atoi(PQgetvalue(res, j, i_tgtype));
7749 				tginfo[j].tgnargs = atoi(PQgetvalue(res, j, i_tgnargs));
7750 				tginfo[j].tgargs = pg_strdup(PQgetvalue(res, j, i_tgargs));
7751 				tginfo[j].tgisconstraint = *(PQgetvalue(res, j, i_tgisconstraint)) == 't';
7752 				tginfo[j].tgdeferrable = *(PQgetvalue(res, j, i_tgdeferrable)) == 't';
7753 				tginfo[j].tginitdeferred = *(PQgetvalue(res, j, i_tginitdeferred)) == 't';
7754 
7755 				if (tginfo[j].tgisconstraint)
7756 				{
7757 					tginfo[j].tgconstrname = pg_strdup(PQgetvalue(res, j, i_tgconstrname));
7758 					tginfo[j].tgconstrrelid = atooid(PQgetvalue(res, j, i_tgconstrrelid));
7759 					if (OidIsValid(tginfo[j].tgconstrrelid))
7760 					{
7761 						if (PQgetisnull(res, j, i_tgconstrrelname))
7762 							exit_horribly(NULL, "query produced null referenced table name for foreign key trigger \"%s\" on table \"%s\" (OID of table: %u)\n",
7763 										  tginfo[j].dobj.name,
7764 										  tbinfo->dobj.name,
7765 										  tginfo[j].tgconstrrelid);
7766 						tginfo[j].tgconstrrelname = pg_strdup(PQgetvalue(res, j, i_tgconstrrelname));
7767 					}
7768 					else
7769 						tginfo[j].tgconstrrelname = NULL;
7770 				}
7771 				else
7772 				{
7773 					tginfo[j].tgconstrname = NULL;
7774 					tginfo[j].tgconstrrelid = InvalidOid;
7775 					tginfo[j].tgconstrrelname = NULL;
7776 				}
7777 			}
7778 		}
7779 
7780 		PQclear(res);
7781 	}
7782 
7783 	destroyPQExpBuffer(query);
7784 }
7785 
7786 /*
7787  * getEventTriggers
7788  *	  get information about event triggers
7789  */
7790 EventTriggerInfo *
getEventTriggers(Archive * fout,int * numEventTriggers)7791 getEventTriggers(Archive *fout, int *numEventTriggers)
7792 {
7793 	int			i;
7794 	PQExpBuffer query;
7795 	PGresult   *res;
7796 	EventTriggerInfo *evtinfo;
7797 	int			i_tableoid,
7798 				i_oid,
7799 				i_evtname,
7800 				i_evtevent,
7801 				i_evtowner,
7802 				i_evttags,
7803 				i_evtfname,
7804 				i_evtenabled;
7805 	int			ntups;
7806 
7807 	/* Before 9.3, there are no event triggers */
7808 	if (fout->remoteVersion < 90300)
7809 	{
7810 		*numEventTriggers = 0;
7811 		return NULL;
7812 	}
7813 
7814 	query = createPQExpBuffer();
7815 
7816 	appendPQExpBuffer(query,
7817 					  "SELECT e.tableoid, e.oid, evtname, evtenabled, "
7818 					  "evtevent, (%s evtowner) AS evtowner, "
7819 					  "array_to_string(array("
7820 					  "select quote_literal(x) "
7821 					  " from unnest(evttags) as t(x)), ', ') as evttags, "
7822 					  "e.evtfoid::regproc as evtfname "
7823 					  "FROM pg_event_trigger e "
7824 					  "ORDER BY e.oid",
7825 					  username_subquery);
7826 
7827 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7828 
7829 	ntups = PQntuples(res);
7830 
7831 	*numEventTriggers = ntups;
7832 
7833 	evtinfo = (EventTriggerInfo *) pg_malloc(ntups * sizeof(EventTriggerInfo));
7834 
7835 	i_tableoid = PQfnumber(res, "tableoid");
7836 	i_oid = PQfnumber(res, "oid");
7837 	i_evtname = PQfnumber(res, "evtname");
7838 	i_evtevent = PQfnumber(res, "evtevent");
7839 	i_evtowner = PQfnumber(res, "evtowner");
7840 	i_evttags = PQfnumber(res, "evttags");
7841 	i_evtfname = PQfnumber(res, "evtfname");
7842 	i_evtenabled = PQfnumber(res, "evtenabled");
7843 
7844 	for (i = 0; i < ntups; i++)
7845 	{
7846 		evtinfo[i].dobj.objType = DO_EVENT_TRIGGER;
7847 		evtinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
7848 		evtinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
7849 		AssignDumpId(&evtinfo[i].dobj);
7850 		evtinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_evtname));
7851 		evtinfo[i].evtname = pg_strdup(PQgetvalue(res, i, i_evtname));
7852 		evtinfo[i].evtevent = pg_strdup(PQgetvalue(res, i, i_evtevent));
7853 		evtinfo[i].evtowner = pg_strdup(PQgetvalue(res, i, i_evtowner));
7854 		evtinfo[i].evttags = pg_strdup(PQgetvalue(res, i, i_evttags));
7855 		evtinfo[i].evtfname = pg_strdup(PQgetvalue(res, i, i_evtfname));
7856 		evtinfo[i].evtenabled = *(PQgetvalue(res, i, i_evtenabled));
7857 
7858 		/* Decide whether we want to dump it */
7859 		selectDumpableObject(&(evtinfo[i].dobj), fout);
7860 
7861 		/* Event Triggers do not currently have ACLs. */
7862 		evtinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
7863 	}
7864 
7865 	PQclear(res);
7866 
7867 	destroyPQExpBuffer(query);
7868 
7869 	return evtinfo;
7870 }
7871 
7872 /*
7873  * getProcLangs
7874  *	  get basic information about every procedural language in the system
7875  *
7876  * numProcLangs is set to the number of langs read in
7877  *
7878  * NB: this must run after getFuncs() because we assume we can do
7879  * findFuncByOid().
7880  */
7881 ProcLangInfo *
getProcLangs(Archive * fout,int * numProcLangs)7882 getProcLangs(Archive *fout, int *numProcLangs)
7883 {
7884 	DumpOptions *dopt = fout->dopt;
7885 	PGresult   *res;
7886 	int			ntups;
7887 	int			i;
7888 	PQExpBuffer query = createPQExpBuffer();
7889 	ProcLangInfo *planginfo;
7890 	int			i_tableoid;
7891 	int			i_oid;
7892 	int			i_lanname;
7893 	int			i_lanpltrusted;
7894 	int			i_lanplcallfoid;
7895 	int			i_laninline;
7896 	int			i_lanvalidator;
7897 	int			i_lanacl;
7898 	int			i_rlanacl;
7899 	int			i_initlanacl;
7900 	int			i_initrlanacl;
7901 	int			i_lanowner;
7902 
7903 	if (fout->remoteVersion >= 90600)
7904 	{
7905 		PQExpBuffer acl_subquery = createPQExpBuffer();
7906 		PQExpBuffer racl_subquery = createPQExpBuffer();
7907 		PQExpBuffer initacl_subquery = createPQExpBuffer();
7908 		PQExpBuffer initracl_subquery = createPQExpBuffer();
7909 
7910 		buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
7911 						initracl_subquery, "l.lanacl", "l.lanowner", "'l'",
7912 						dopt->binary_upgrade);
7913 
7914 		/* pg_language has a laninline column */
7915 		appendPQExpBuffer(query, "SELECT l.tableoid, l.oid, "
7916 						  "l.lanname, l.lanpltrusted, l.lanplcallfoid, "
7917 						  "l.laninline, l.lanvalidator, "
7918 						  "%s AS lanacl, "
7919 						  "%s AS rlanacl, "
7920 						  "%s AS initlanacl, "
7921 						  "%s AS initrlanacl, "
7922 						  "(%s l.lanowner) AS lanowner "
7923 						  "FROM pg_language l "
7924 						  "LEFT JOIN pg_init_privs pip ON "
7925 						  "(l.oid = pip.objoid "
7926 						  "AND pip.classoid = 'pg_language'::regclass "
7927 						  "AND pip.objsubid = 0) "
7928 						  "WHERE l.lanispl "
7929 						  "ORDER BY l.oid",
7930 						  acl_subquery->data,
7931 						  racl_subquery->data,
7932 						  initacl_subquery->data,
7933 						  initracl_subquery->data,
7934 						  username_subquery);
7935 
7936 		destroyPQExpBuffer(acl_subquery);
7937 		destroyPQExpBuffer(racl_subquery);
7938 		destroyPQExpBuffer(initacl_subquery);
7939 		destroyPQExpBuffer(initracl_subquery);
7940 	}
7941 	else if (fout->remoteVersion >= 90000)
7942 	{
7943 		/* pg_language has a laninline column */
7944 		appendPQExpBuffer(query, "SELECT tableoid, oid, "
7945 						  "lanname, lanpltrusted, lanplcallfoid, "
7946 						  "laninline, lanvalidator, lanacl, NULL AS rlanacl, "
7947 						  "NULL AS initlanacl, NULL AS initrlanacl, "
7948 						  "(%s lanowner) AS lanowner "
7949 						  "FROM pg_language "
7950 						  "WHERE lanispl "
7951 						  "ORDER BY oid",
7952 						  username_subquery);
7953 	}
7954 	else if (fout->remoteVersion >= 80300)
7955 	{
7956 		/* pg_language has a lanowner column */
7957 		appendPQExpBuffer(query, "SELECT tableoid, oid, "
7958 						  "lanname, lanpltrusted, lanplcallfoid, "
7959 						  "0 AS laninline, lanvalidator, lanacl, "
7960 						  "NULL AS rlanacl, "
7961 						  "NULL AS initlanacl, NULL AS initrlanacl, "
7962 						  "(%s lanowner) AS lanowner "
7963 						  "FROM pg_language "
7964 						  "WHERE lanispl "
7965 						  "ORDER BY oid",
7966 						  username_subquery);
7967 	}
7968 	else if (fout->remoteVersion >= 80100)
7969 	{
7970 		/* Languages are owned by the bootstrap superuser, OID 10 */
7971 		appendPQExpBuffer(query, "SELECT tableoid, oid, "
7972 						  "lanname, lanpltrusted, lanplcallfoid, "
7973 						  "0 AS laninline, lanvalidator, lanacl, "
7974 						  "NULL AS rlanacl, "
7975 						  "NULL AS initlanacl, NULL AS initrlanacl, "
7976 						  "(%s '10') AS lanowner "
7977 						  "FROM pg_language "
7978 						  "WHERE lanispl "
7979 						  "ORDER BY oid",
7980 						  username_subquery);
7981 	}
7982 	else
7983 	{
7984 		/* Languages are owned by the bootstrap superuser, sysid 1 */
7985 		appendPQExpBuffer(query, "SELECT tableoid, oid, "
7986 						  "lanname, lanpltrusted, lanplcallfoid, "
7987 						  "0 AS laninline, lanvalidator, lanacl, "
7988 						  "NULL AS rlanacl, "
7989 						  "NULL AS initlanacl, NULL AS initrlanacl, "
7990 						  "(%s '1') AS lanowner "
7991 						  "FROM pg_language "
7992 						  "WHERE lanispl "
7993 						  "ORDER BY oid",
7994 						  username_subquery);
7995 	}
7996 
7997 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
7998 
7999 	ntups = PQntuples(res);
8000 
8001 	*numProcLangs = ntups;
8002 
8003 	planginfo = (ProcLangInfo *) pg_malloc(ntups * sizeof(ProcLangInfo));
8004 
8005 	i_tableoid = PQfnumber(res, "tableoid");
8006 	i_oid = PQfnumber(res, "oid");
8007 	i_lanname = PQfnumber(res, "lanname");
8008 	i_lanpltrusted = PQfnumber(res, "lanpltrusted");
8009 	i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
8010 	i_laninline = PQfnumber(res, "laninline");
8011 	i_lanvalidator = PQfnumber(res, "lanvalidator");
8012 	i_lanacl = PQfnumber(res, "lanacl");
8013 	i_rlanacl = PQfnumber(res, "rlanacl");
8014 	i_initlanacl = PQfnumber(res, "initlanacl");
8015 	i_initrlanacl = PQfnumber(res, "initrlanacl");
8016 	i_lanowner = PQfnumber(res, "lanowner");
8017 
8018 	for (i = 0; i < ntups; i++)
8019 	{
8020 		planginfo[i].dobj.objType = DO_PROCLANG;
8021 		planginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8022 		planginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8023 		AssignDumpId(&planginfo[i].dobj);
8024 
8025 		planginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_lanname));
8026 		planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
8027 		planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
8028 		planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
8029 		planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
8030 		planginfo[i].lanacl = pg_strdup(PQgetvalue(res, i, i_lanacl));
8031 		planginfo[i].rlanacl = pg_strdup(PQgetvalue(res, i, i_rlanacl));
8032 		planginfo[i].initlanacl = pg_strdup(PQgetvalue(res, i, i_initlanacl));
8033 		planginfo[i].initrlanacl = pg_strdup(PQgetvalue(res, i, i_initrlanacl));
8034 		planginfo[i].lanowner = pg_strdup(PQgetvalue(res, i, i_lanowner));
8035 
8036 		/* Decide whether we want to dump it */
8037 		selectDumpableProcLang(&(planginfo[i]), fout);
8038 
8039 		/* Do not try to dump ACL if no ACL exists. */
8040 		if (PQgetisnull(res, i, i_lanacl) && PQgetisnull(res, i, i_rlanacl) &&
8041 			PQgetisnull(res, i, i_initlanacl) &&
8042 			PQgetisnull(res, i, i_initrlanacl))
8043 			planginfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8044 	}
8045 
8046 	PQclear(res);
8047 
8048 	destroyPQExpBuffer(query);
8049 
8050 	return planginfo;
8051 }
8052 
8053 /*
8054  * getCasts
8055  *	  get basic information about every cast in the system
8056  *
8057  * numCasts is set to the number of casts read in
8058  */
8059 CastInfo *
getCasts(Archive * fout,int * numCasts)8060 getCasts(Archive *fout, int *numCasts)
8061 {
8062 	PGresult   *res;
8063 	int			ntups;
8064 	int			i;
8065 	PQExpBuffer query = createPQExpBuffer();
8066 	CastInfo   *castinfo;
8067 	int			i_tableoid;
8068 	int			i_oid;
8069 	int			i_castsource;
8070 	int			i_casttarget;
8071 	int			i_castfunc;
8072 	int			i_castcontext;
8073 	int			i_castmethod;
8074 
8075 	if (fout->remoteVersion >= 80400)
8076 	{
8077 		appendPQExpBufferStr(query, "SELECT tableoid, oid, "
8078 							 "castsource, casttarget, castfunc, castcontext, "
8079 							 "castmethod "
8080 							 "FROM pg_cast ORDER BY 3,4");
8081 	}
8082 	else
8083 	{
8084 		appendPQExpBufferStr(query, "SELECT tableoid, oid, "
8085 							 "castsource, casttarget, castfunc, castcontext, "
8086 							 "CASE WHEN castfunc = 0 THEN 'b' ELSE 'f' END AS castmethod "
8087 							 "FROM pg_cast ORDER BY 3,4");
8088 	}
8089 
8090 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8091 
8092 	ntups = PQntuples(res);
8093 
8094 	*numCasts = ntups;
8095 
8096 	castinfo = (CastInfo *) pg_malloc(ntups * sizeof(CastInfo));
8097 
8098 	i_tableoid = PQfnumber(res, "tableoid");
8099 	i_oid = PQfnumber(res, "oid");
8100 	i_castsource = PQfnumber(res, "castsource");
8101 	i_casttarget = PQfnumber(res, "casttarget");
8102 	i_castfunc = PQfnumber(res, "castfunc");
8103 	i_castcontext = PQfnumber(res, "castcontext");
8104 	i_castmethod = PQfnumber(res, "castmethod");
8105 
8106 	for (i = 0; i < ntups; i++)
8107 	{
8108 		PQExpBufferData namebuf;
8109 		TypeInfo   *sTypeInfo;
8110 		TypeInfo   *tTypeInfo;
8111 
8112 		castinfo[i].dobj.objType = DO_CAST;
8113 		castinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8114 		castinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8115 		AssignDumpId(&castinfo[i].dobj);
8116 		castinfo[i].castsource = atooid(PQgetvalue(res, i, i_castsource));
8117 		castinfo[i].casttarget = atooid(PQgetvalue(res, i, i_casttarget));
8118 		castinfo[i].castfunc = atooid(PQgetvalue(res, i, i_castfunc));
8119 		castinfo[i].castcontext = *(PQgetvalue(res, i, i_castcontext));
8120 		castinfo[i].castmethod = *(PQgetvalue(res, i, i_castmethod));
8121 
8122 		/*
8123 		 * Try to name cast as concatenation of typnames.  This is only used
8124 		 * for purposes of sorting.  If we fail to find either type, the name
8125 		 * will be an empty string.
8126 		 */
8127 		initPQExpBuffer(&namebuf);
8128 		sTypeInfo = findTypeByOid(castinfo[i].castsource);
8129 		tTypeInfo = findTypeByOid(castinfo[i].casttarget);
8130 		if (sTypeInfo && tTypeInfo)
8131 			appendPQExpBuffer(&namebuf, "%s %s",
8132 							  sTypeInfo->dobj.name, tTypeInfo->dobj.name);
8133 		castinfo[i].dobj.name = namebuf.data;
8134 
8135 		/* Decide whether we want to dump it */
8136 		selectDumpableCast(&(castinfo[i]), fout);
8137 
8138 		/* Casts do not currently have ACLs. */
8139 		castinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8140 	}
8141 
8142 	PQclear(res);
8143 
8144 	destroyPQExpBuffer(query);
8145 
8146 	return castinfo;
8147 }
8148 
8149 static char *
get_language_name(Archive * fout,Oid langid)8150 get_language_name(Archive *fout, Oid langid)
8151 {
8152 	PQExpBuffer query;
8153 	PGresult   *res;
8154 	char	   *lanname;
8155 
8156 	query = createPQExpBuffer();
8157 	appendPQExpBuffer(query, "SELECT lanname FROM pg_language WHERE oid = %u", langid);
8158 	res = ExecuteSqlQueryForSingleRow(fout, query->data);
8159 	lanname = pg_strdup(fmtId(PQgetvalue(res, 0, 0)));
8160 	destroyPQExpBuffer(query);
8161 	PQclear(res);
8162 
8163 	return lanname;
8164 }
8165 
8166 /*
8167  * getTransforms
8168  *	  get basic information about every transform in the system
8169  *
8170  * numTransforms is set to the number of transforms read in
8171  */
8172 TransformInfo *
getTransforms(Archive * fout,int * numTransforms)8173 getTransforms(Archive *fout, int *numTransforms)
8174 {
8175 	PGresult   *res;
8176 	int			ntups;
8177 	int			i;
8178 	PQExpBuffer query;
8179 	TransformInfo *transforminfo;
8180 	int			i_tableoid;
8181 	int			i_oid;
8182 	int			i_trftype;
8183 	int			i_trflang;
8184 	int			i_trffromsql;
8185 	int			i_trftosql;
8186 
8187 	/* Transforms didn't exist pre-9.5 */
8188 	if (fout->remoteVersion < 90500)
8189 	{
8190 		*numTransforms = 0;
8191 		return NULL;
8192 	}
8193 
8194 	query = createPQExpBuffer();
8195 
8196 	appendPQExpBuffer(query, "SELECT tableoid, oid, "
8197 					  "trftype, trflang, trffromsql::oid, trftosql::oid "
8198 					  "FROM pg_transform "
8199 					  "ORDER BY 3,4");
8200 
8201 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8202 
8203 	ntups = PQntuples(res);
8204 
8205 	*numTransforms = ntups;
8206 
8207 	transforminfo = (TransformInfo *) pg_malloc(ntups * sizeof(TransformInfo));
8208 
8209 	i_tableoid = PQfnumber(res, "tableoid");
8210 	i_oid = PQfnumber(res, "oid");
8211 	i_trftype = PQfnumber(res, "trftype");
8212 	i_trflang = PQfnumber(res, "trflang");
8213 	i_trffromsql = PQfnumber(res, "trffromsql");
8214 	i_trftosql = PQfnumber(res, "trftosql");
8215 
8216 	for (i = 0; i < ntups; i++)
8217 	{
8218 		PQExpBufferData namebuf;
8219 		TypeInfo   *typeInfo;
8220 		char	   *lanname;
8221 
8222 		transforminfo[i].dobj.objType = DO_TRANSFORM;
8223 		transforminfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8224 		transforminfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8225 		AssignDumpId(&transforminfo[i].dobj);
8226 		transforminfo[i].trftype = atooid(PQgetvalue(res, i, i_trftype));
8227 		transforminfo[i].trflang = atooid(PQgetvalue(res, i, i_trflang));
8228 		transforminfo[i].trffromsql = atooid(PQgetvalue(res, i, i_trffromsql));
8229 		transforminfo[i].trftosql = atooid(PQgetvalue(res, i, i_trftosql));
8230 
8231 		/*
8232 		 * Try to name transform as concatenation of type and language name.
8233 		 * This is only used for purposes of sorting.  If we fail to find
8234 		 * either, the name will be an empty string.
8235 		 */
8236 		initPQExpBuffer(&namebuf);
8237 		typeInfo = findTypeByOid(transforminfo[i].trftype);
8238 		lanname = get_language_name(fout, transforminfo[i].trflang);
8239 		if (typeInfo && lanname)
8240 			appendPQExpBuffer(&namebuf, "%s %s",
8241 							  typeInfo->dobj.name, lanname);
8242 		transforminfo[i].dobj.name = namebuf.data;
8243 		free(lanname);
8244 
8245 		/* Decide whether we want to dump it */
8246 		selectDumpableObject(&(transforminfo[i].dobj), fout);
8247 	}
8248 
8249 	PQclear(res);
8250 
8251 	destroyPQExpBuffer(query);
8252 
8253 	return transforminfo;
8254 }
8255 
8256 /*
8257  * getTableAttrs -
8258  *	  for each interesting table, read info about its attributes
8259  *	  (names, types, default values, CHECK constraints, etc)
8260  *
8261  * This is implemented in a very inefficient way right now, looping
8262  * through the tblinfo and doing a join per table to find the attrs and their
8263  * types.  However, because we want type names and so forth to be named
8264  * relative to the schema of each table, we couldn't do it in just one
8265  * query.  (Maybe one query per schema?)
8266  *
8267  *	modifies tblinfo
8268  */
8269 void
getTableAttrs(Archive * fout,TableInfo * tblinfo,int numTables)8270 getTableAttrs(Archive *fout, TableInfo *tblinfo, int numTables)
8271 {
8272 	DumpOptions *dopt = fout->dopt;
8273 	int			i,
8274 				j;
8275 	PQExpBuffer q = createPQExpBuffer();
8276 	int			i_attnum;
8277 	int			i_attname;
8278 	int			i_atttypname;
8279 	int			i_atttypmod;
8280 	int			i_attstattarget;
8281 	int			i_attstorage;
8282 	int			i_typstorage;
8283 	int			i_attnotnull;
8284 	int			i_atthasdef;
8285 	int			i_attidentity;
8286 	int			i_attisdropped;
8287 	int			i_attlen;
8288 	int			i_attalign;
8289 	int			i_attislocal;
8290 	int			i_attoptions;
8291 	int			i_attcollation;
8292 	int			i_attfdwoptions;
8293 	int			i_attmissingval;
8294 	PGresult   *res;
8295 	int			ntups;
8296 	bool		hasdefaults;
8297 
8298 	for (i = 0; i < numTables; i++)
8299 	{
8300 		TableInfo  *tbinfo = &tblinfo[i];
8301 
8302 		/* Don't bother to collect info for sequences */
8303 		if (tbinfo->relkind == RELKIND_SEQUENCE)
8304 			continue;
8305 
8306 		/* Don't bother with uninteresting tables, either */
8307 		if (!tbinfo->interesting)
8308 			continue;
8309 
8310 		/* find all the user attributes and their types */
8311 
8312 		/*
8313 		 * we must read the attribute names in attribute number order! because
8314 		 * we will use the attnum to index into the attnames array later.
8315 		 */
8316 		if (g_verbose)
8317 			write_msg(NULL, "finding the columns and types of table \"%s.%s\"\n",
8318 					  tbinfo->dobj.namespace->dobj.name,
8319 					  tbinfo->dobj.name);
8320 
8321 		resetPQExpBuffer(q);
8322 
8323 		if (fout->remoteVersion >= 110000)
8324 		{
8325 			/* atthasmissing and attmissingval are new in 11 */
8326 			appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
8327 							  "a.attstattarget, a.attstorage, t.typstorage, "
8328 							  "a.attnotnull, a.atthasdef, a.attisdropped, "
8329 							  "a.attlen, a.attalign, a.attislocal, "
8330 							  "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
8331 							  "array_to_string(a.attoptions, ', ') AS attoptions, "
8332 							  "CASE WHEN a.attcollation <> t.typcollation "
8333 							  "THEN a.attcollation ELSE 0 END AS attcollation, "
8334 							  "a.attidentity, "
8335 							  "pg_catalog.array_to_string(ARRAY("
8336 							  "SELECT pg_catalog.quote_ident(option_name) || "
8337 							  "' ' || pg_catalog.quote_literal(option_value) "
8338 							  "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
8339 							  "ORDER BY option_name"
8340 							  "), E',\n    ') AS attfdwoptions ,"
8341 							  "CASE WHEN a.atthasmissing AND NOT a.attisdropped "
8342 							  "THEN a.attmissingval ELSE null END AS attmissingval "
8343 							  "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
8344 							  "ON a.atttypid = t.oid "
8345 							  "WHERE a.attrelid = '%u'::pg_catalog.oid "
8346 							  "AND a.attnum > 0::pg_catalog.int2 "
8347 							  "ORDER BY a.attnum",
8348 							  tbinfo->dobj.catId.oid);
8349 		}
8350 		else if (fout->remoteVersion >= 100000)
8351 		{
8352 			/*
8353 			 * attidentity is new in version 10.
8354 			 */
8355 			appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
8356 							  "a.attstattarget, a.attstorage, t.typstorage, "
8357 							  "a.attnotnull, a.atthasdef, a.attisdropped, "
8358 							  "a.attlen, a.attalign, a.attislocal, "
8359 							  "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
8360 							  "array_to_string(a.attoptions, ', ') AS attoptions, "
8361 							  "CASE WHEN a.attcollation <> t.typcollation "
8362 							  "THEN a.attcollation ELSE 0 END AS attcollation, "
8363 							  "a.attidentity, "
8364 							  "pg_catalog.array_to_string(ARRAY("
8365 							  "SELECT pg_catalog.quote_ident(option_name) || "
8366 							  "' ' || pg_catalog.quote_literal(option_value) "
8367 							  "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
8368 							  "ORDER BY option_name"
8369 							  "), E',\n    ') AS attfdwoptions ,"
8370 							  "NULL as attmissingval "
8371 							  "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
8372 							  "ON a.atttypid = t.oid "
8373 							  "WHERE a.attrelid = '%u'::pg_catalog.oid "
8374 							  "AND a.attnum > 0::pg_catalog.int2 "
8375 							  "ORDER BY a.attnum",
8376 							  tbinfo->dobj.catId.oid);
8377 		}
8378 		else if (fout->remoteVersion >= 90200)
8379 		{
8380 			/*
8381 			 * attfdwoptions is new in 9.2.
8382 			 */
8383 			appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
8384 							  "a.attstattarget, a.attstorage, t.typstorage, "
8385 							  "a.attnotnull, a.atthasdef, a.attisdropped, "
8386 							  "a.attlen, a.attalign, a.attislocal, "
8387 							  "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
8388 							  "array_to_string(a.attoptions, ', ') AS attoptions, "
8389 							  "CASE WHEN a.attcollation <> t.typcollation "
8390 							  "THEN a.attcollation ELSE 0 END AS attcollation, "
8391 							  "pg_catalog.array_to_string(ARRAY("
8392 							  "SELECT pg_catalog.quote_ident(option_name) || "
8393 							  "' ' || pg_catalog.quote_literal(option_value) "
8394 							  "FROM pg_catalog.pg_options_to_table(attfdwoptions) "
8395 							  "ORDER BY option_name"
8396 							  "), E',\n    ') AS attfdwoptions, "
8397 							  "NULL as attmissingval "
8398 							  "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
8399 							  "ON a.atttypid = t.oid "
8400 							  "WHERE a.attrelid = '%u'::pg_catalog.oid "
8401 							  "AND a.attnum > 0::pg_catalog.int2 "
8402 							  "ORDER BY a.attnum",
8403 							  tbinfo->dobj.catId.oid);
8404 		}
8405 		else if (fout->remoteVersion >= 90100)
8406 		{
8407 			/*
8408 			 * attcollation is new in 9.1.  Since we only want to dump COLLATE
8409 			 * clauses for attributes whose collation is different from their
8410 			 * type's default, we use a CASE here to suppress uninteresting
8411 			 * attcollations cheaply.
8412 			 */
8413 			appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
8414 							  "a.attstattarget, a.attstorage, t.typstorage, "
8415 							  "a.attnotnull, a.atthasdef, a.attisdropped, "
8416 							  "a.attlen, a.attalign, a.attislocal, "
8417 							  "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
8418 							  "array_to_string(a.attoptions, ', ') AS attoptions, "
8419 							  "CASE WHEN a.attcollation <> t.typcollation "
8420 							  "THEN a.attcollation ELSE 0 END AS attcollation, "
8421 							  "NULL AS attfdwoptions, "
8422 							  "NULL as attmissingval "
8423 							  "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
8424 							  "ON a.atttypid = t.oid "
8425 							  "WHERE a.attrelid = '%u'::pg_catalog.oid "
8426 							  "AND a.attnum > 0::pg_catalog.int2 "
8427 							  "ORDER BY a.attnum",
8428 							  tbinfo->dobj.catId.oid);
8429 		}
8430 		else if (fout->remoteVersion >= 90000)
8431 		{
8432 			/* attoptions is new in 9.0 */
8433 			appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
8434 							  "a.attstattarget, a.attstorage, t.typstorage, "
8435 							  "a.attnotnull, a.atthasdef, a.attisdropped, "
8436 							  "a.attlen, a.attalign, a.attislocal, "
8437 							  "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
8438 							  "array_to_string(a.attoptions, ', ') AS attoptions, "
8439 							  "0 AS attcollation, "
8440 							  "NULL AS attfdwoptions, "
8441 							  "NULL as attmissingval "
8442 							  "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
8443 							  "ON a.atttypid = t.oid "
8444 							  "WHERE a.attrelid = '%u'::pg_catalog.oid "
8445 							  "AND a.attnum > 0::pg_catalog.int2 "
8446 							  "ORDER BY a.attnum",
8447 							  tbinfo->dobj.catId.oid);
8448 		}
8449 		else
8450 		{
8451 			/* need left join here to not fail on dropped columns ... */
8452 			appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, "
8453 							  "a.attstattarget, a.attstorage, t.typstorage, "
8454 							  "a.attnotnull, a.atthasdef, a.attisdropped, "
8455 							  "a.attlen, a.attalign, a.attislocal, "
8456 							  "pg_catalog.format_type(t.oid,a.atttypmod) AS atttypname, "
8457 							  "'' AS attoptions, 0 AS attcollation, "
8458 							  "NULL AS attfdwoptions, "
8459 							  "NULL as attmissingval "
8460 							  "FROM pg_catalog.pg_attribute a LEFT JOIN pg_catalog.pg_type t "
8461 							  "ON a.atttypid = t.oid "
8462 							  "WHERE a.attrelid = '%u'::pg_catalog.oid "
8463 							  "AND a.attnum > 0::pg_catalog.int2 "
8464 							  "ORDER BY a.attnum",
8465 							  tbinfo->dobj.catId.oid);
8466 		}
8467 
8468 		res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
8469 
8470 		ntups = PQntuples(res);
8471 
8472 		i_attnum = PQfnumber(res, "attnum");
8473 		i_attname = PQfnumber(res, "attname");
8474 		i_atttypname = PQfnumber(res, "atttypname");
8475 		i_atttypmod = PQfnumber(res, "atttypmod");
8476 		i_attstattarget = PQfnumber(res, "attstattarget");
8477 		i_attstorage = PQfnumber(res, "attstorage");
8478 		i_typstorage = PQfnumber(res, "typstorage");
8479 		i_attnotnull = PQfnumber(res, "attnotnull");
8480 		i_atthasdef = PQfnumber(res, "atthasdef");
8481 		i_attidentity = PQfnumber(res, "attidentity");
8482 		i_attisdropped = PQfnumber(res, "attisdropped");
8483 		i_attlen = PQfnumber(res, "attlen");
8484 		i_attalign = PQfnumber(res, "attalign");
8485 		i_attislocal = PQfnumber(res, "attislocal");
8486 		i_attoptions = PQfnumber(res, "attoptions");
8487 		i_attcollation = PQfnumber(res, "attcollation");
8488 		i_attfdwoptions = PQfnumber(res, "attfdwoptions");
8489 		i_attmissingval = PQfnumber(res, "attmissingval");
8490 
8491 		tbinfo->numatts = ntups;
8492 		tbinfo->attnames = (char **) pg_malloc(ntups * sizeof(char *));
8493 		tbinfo->atttypnames = (char **) pg_malloc(ntups * sizeof(char *));
8494 		tbinfo->atttypmod = (int *) pg_malloc(ntups * sizeof(int));
8495 		tbinfo->attstattarget = (int *) pg_malloc(ntups * sizeof(int));
8496 		tbinfo->attstorage = (char *) pg_malloc(ntups * sizeof(char));
8497 		tbinfo->typstorage = (char *) pg_malloc(ntups * sizeof(char));
8498 		tbinfo->attidentity = (char *) pg_malloc(ntups * sizeof(char));
8499 		tbinfo->attisdropped = (bool *) pg_malloc(ntups * sizeof(bool));
8500 		tbinfo->attlen = (int *) pg_malloc(ntups * sizeof(int));
8501 		tbinfo->attalign = (char *) pg_malloc(ntups * sizeof(char));
8502 		tbinfo->attislocal = (bool *) pg_malloc(ntups * sizeof(bool));
8503 		tbinfo->attoptions = (char **) pg_malloc(ntups * sizeof(char *));
8504 		tbinfo->attcollation = (Oid *) pg_malloc(ntups * sizeof(Oid));
8505 		tbinfo->attfdwoptions = (char **) pg_malloc(ntups * sizeof(char *));
8506 		tbinfo->attmissingval = (char **) pg_malloc(ntups * sizeof(char *));
8507 		tbinfo->notnull = (bool *) pg_malloc(ntups * sizeof(bool));
8508 		tbinfo->inhNotNull = (bool *) pg_malloc(ntups * sizeof(bool));
8509 		tbinfo->attrdefs = (AttrDefInfo **) pg_malloc(ntups * sizeof(AttrDefInfo *));
8510 		hasdefaults = false;
8511 
8512 		for (j = 0; j < ntups; j++)
8513 		{
8514 			if (j + 1 != atoi(PQgetvalue(res, j, i_attnum)))
8515 				exit_horribly(NULL,
8516 							  "invalid column numbering in table \"%s\"\n",
8517 							  tbinfo->dobj.name);
8518 			tbinfo->attnames[j] = pg_strdup(PQgetvalue(res, j, i_attname));
8519 			tbinfo->atttypnames[j] = pg_strdup(PQgetvalue(res, j, i_atttypname));
8520 			tbinfo->atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod));
8521 			tbinfo->attstattarget[j] = atoi(PQgetvalue(res, j, i_attstattarget));
8522 			tbinfo->attstorage[j] = *(PQgetvalue(res, j, i_attstorage));
8523 			tbinfo->typstorage[j] = *(PQgetvalue(res, j, i_typstorage));
8524 			tbinfo->attidentity[j] = (i_attidentity >= 0 ? *(PQgetvalue(res, j, i_attidentity)) : '\0');
8525 			tbinfo->needs_override = tbinfo->needs_override || (tbinfo->attidentity[j] == ATTRIBUTE_IDENTITY_ALWAYS);
8526 			tbinfo->attisdropped[j] = (PQgetvalue(res, j, i_attisdropped)[0] == 't');
8527 			tbinfo->attlen[j] = atoi(PQgetvalue(res, j, i_attlen));
8528 			tbinfo->attalign[j] = *(PQgetvalue(res, j, i_attalign));
8529 			tbinfo->attislocal[j] = (PQgetvalue(res, j, i_attislocal)[0] == 't');
8530 			tbinfo->notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't');
8531 			tbinfo->attoptions[j] = pg_strdup(PQgetvalue(res, j, i_attoptions));
8532 			tbinfo->attcollation[j] = atooid(PQgetvalue(res, j, i_attcollation));
8533 			tbinfo->attfdwoptions[j] = pg_strdup(PQgetvalue(res, j, i_attfdwoptions));
8534 			tbinfo->attmissingval[j] = pg_strdup(PQgetvalue(res, j, i_attmissingval));
8535 			tbinfo->attrdefs[j] = NULL; /* fix below */
8536 			if (PQgetvalue(res, j, i_atthasdef)[0] == 't')
8537 				hasdefaults = true;
8538 			/* these flags will be set in flagInhAttrs() */
8539 			tbinfo->inhNotNull[j] = false;
8540 		}
8541 
8542 		PQclear(res);
8543 
8544 		/*
8545 		 * Get info about column defaults
8546 		 */
8547 		if (hasdefaults)
8548 		{
8549 			AttrDefInfo *attrdefs;
8550 			int			numDefaults;
8551 
8552 			if (g_verbose)
8553 				write_msg(NULL, "finding default expressions of table \"%s.%s\"\n",
8554 						  tbinfo->dobj.namespace->dobj.name,
8555 						  tbinfo->dobj.name);
8556 
8557 			printfPQExpBuffer(q, "SELECT tableoid, oid, adnum, "
8558 							  "pg_catalog.pg_get_expr(adbin, adrelid) AS adsrc "
8559 							  "FROM pg_catalog.pg_attrdef "
8560 							  "WHERE adrelid = '%u'::pg_catalog.oid",
8561 							  tbinfo->dobj.catId.oid);
8562 
8563 			res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
8564 
8565 			numDefaults = PQntuples(res);
8566 			attrdefs = (AttrDefInfo *) pg_malloc(numDefaults * sizeof(AttrDefInfo));
8567 
8568 			for (j = 0; j < numDefaults; j++)
8569 			{
8570 				int			adnum;
8571 
8572 				adnum = atoi(PQgetvalue(res, j, 2));
8573 
8574 				if (adnum <= 0 || adnum > ntups)
8575 					exit_horribly(NULL,
8576 								  "invalid adnum value %d for table \"%s\"\n",
8577 								  adnum, tbinfo->dobj.name);
8578 
8579 				/*
8580 				 * dropped columns shouldn't have defaults, but just in case,
8581 				 * ignore 'em
8582 				 */
8583 				if (tbinfo->attisdropped[adnum - 1])
8584 					continue;
8585 
8586 				attrdefs[j].dobj.objType = DO_ATTRDEF;
8587 				attrdefs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
8588 				attrdefs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
8589 				AssignDumpId(&attrdefs[j].dobj);
8590 				attrdefs[j].adtable = tbinfo;
8591 				attrdefs[j].adnum = adnum;
8592 				attrdefs[j].adef_expr = pg_strdup(PQgetvalue(res, j, 3));
8593 
8594 				attrdefs[j].dobj.name = pg_strdup(tbinfo->dobj.name);
8595 				attrdefs[j].dobj.namespace = tbinfo->dobj.namespace;
8596 
8597 				attrdefs[j].dobj.dump = tbinfo->dobj.dump;
8598 
8599 				/*
8600 				 * Defaults on a VIEW must always be dumped as separate ALTER
8601 				 * TABLE commands.  Defaults on regular tables are dumped as
8602 				 * part of the CREATE TABLE if possible, which it won't be if
8603 				 * the column is not going to be emitted explicitly.
8604 				 */
8605 				if (tbinfo->relkind == RELKIND_VIEW)
8606 				{
8607 					attrdefs[j].separate = true;
8608 				}
8609 				else if (!shouldPrintColumn(dopt, tbinfo, adnum - 1))
8610 				{
8611 					/* column will be suppressed, print default separately */
8612 					attrdefs[j].separate = true;
8613 				}
8614 				else
8615 				{
8616 					attrdefs[j].separate = false;
8617 
8618 					/*
8619 					 * Mark the default as needing to appear before the table,
8620 					 * so that any dependencies it has must be emitted before
8621 					 * the CREATE TABLE.  If this is not possible, we'll
8622 					 * change to "separate" mode while sorting dependencies.
8623 					 */
8624 					addObjectDependency(&tbinfo->dobj,
8625 										attrdefs[j].dobj.dumpId);
8626 				}
8627 
8628 				tbinfo->attrdefs[adnum - 1] = &attrdefs[j];
8629 			}
8630 			PQclear(res);
8631 		}
8632 
8633 		/*
8634 		 * Get info about table CHECK constraints
8635 		 */
8636 		if (tbinfo->ncheck > 0)
8637 		{
8638 			ConstraintInfo *constrs;
8639 			int			numConstrs;
8640 
8641 			if (g_verbose)
8642 				write_msg(NULL, "finding check constraints for table \"%s.%s\"\n",
8643 						  tbinfo->dobj.namespace->dobj.name,
8644 						  tbinfo->dobj.name);
8645 
8646 			resetPQExpBuffer(q);
8647 			if (fout->remoteVersion >= 90200)
8648 			{
8649 				/*
8650 				 * convalidated is new in 9.2 (actually, it is there in 9.1,
8651 				 * but it wasn't ever false for check constraints until 9.2).
8652 				 */
8653 				appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
8654 								  "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
8655 								  "conislocal, convalidated "
8656 								  "FROM pg_catalog.pg_constraint "
8657 								  "WHERE conrelid = '%u'::pg_catalog.oid "
8658 								  "   AND contype = 'c' "
8659 								  "ORDER BY conname",
8660 								  tbinfo->dobj.catId.oid);
8661 			}
8662 			else if (fout->remoteVersion >= 80400)
8663 			{
8664 				/* conislocal is new in 8.4 */
8665 				appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
8666 								  "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
8667 								  "conislocal, true AS convalidated "
8668 								  "FROM pg_catalog.pg_constraint "
8669 								  "WHERE conrelid = '%u'::pg_catalog.oid "
8670 								  "   AND contype = 'c' "
8671 								  "ORDER BY conname",
8672 								  tbinfo->dobj.catId.oid);
8673 			}
8674 			else
8675 			{
8676 				appendPQExpBuffer(q, "SELECT tableoid, oid, conname, "
8677 								  "pg_catalog.pg_get_constraintdef(oid) AS consrc, "
8678 								  "true AS conislocal, true AS convalidated "
8679 								  "FROM pg_catalog.pg_constraint "
8680 								  "WHERE conrelid = '%u'::pg_catalog.oid "
8681 								  "   AND contype = 'c' "
8682 								  "ORDER BY conname",
8683 								  tbinfo->dobj.catId.oid);
8684 			}
8685 
8686 			res = ExecuteSqlQuery(fout, q->data, PGRES_TUPLES_OK);
8687 
8688 			numConstrs = PQntuples(res);
8689 			if (numConstrs != tbinfo->ncheck)
8690 			{
8691 				write_msg(NULL, ngettext("expected %d check constraint on table \"%s\" but found %d\n",
8692 										 "expected %d check constraints on table \"%s\" but found %d\n",
8693 										 tbinfo->ncheck),
8694 						  tbinfo->ncheck, tbinfo->dobj.name, numConstrs);
8695 				write_msg(NULL, "(The system catalogs might be corrupted.)\n");
8696 				exit_nicely(1);
8697 			}
8698 
8699 			constrs = (ConstraintInfo *) pg_malloc(numConstrs * sizeof(ConstraintInfo));
8700 			tbinfo->checkexprs = constrs;
8701 
8702 			for (j = 0; j < numConstrs; j++)
8703 			{
8704 				bool		validated = PQgetvalue(res, j, 5)[0] == 't';
8705 
8706 				constrs[j].dobj.objType = DO_CONSTRAINT;
8707 				constrs[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, 0));
8708 				constrs[j].dobj.catId.oid = atooid(PQgetvalue(res, j, 1));
8709 				AssignDumpId(&constrs[j].dobj);
8710 				constrs[j].dobj.name = pg_strdup(PQgetvalue(res, j, 2));
8711 				constrs[j].dobj.namespace = tbinfo->dobj.namespace;
8712 				constrs[j].contable = tbinfo;
8713 				constrs[j].condomain = NULL;
8714 				constrs[j].contype = 'c';
8715 				constrs[j].condef = pg_strdup(PQgetvalue(res, j, 3));
8716 				constrs[j].confrelid = InvalidOid;
8717 				constrs[j].conindex = 0;
8718 				constrs[j].condeferrable = false;
8719 				constrs[j].condeferred = false;
8720 				constrs[j].conislocal = (PQgetvalue(res, j, 4)[0] == 't');
8721 
8722 				/*
8723 				 * An unvalidated constraint needs to be dumped separately, so
8724 				 * that potentially-violating existing data is loaded before
8725 				 * the constraint.
8726 				 */
8727 				constrs[j].separate = !validated;
8728 
8729 				constrs[j].dobj.dump = tbinfo->dobj.dump;
8730 
8731 				/*
8732 				 * Mark the constraint as needing to appear before the table
8733 				 * --- this is so that any other dependencies of the
8734 				 * constraint will be emitted before we try to create the
8735 				 * table.  If the constraint is to be dumped separately, it
8736 				 * will be dumped after data is loaded anyway, so don't do it.
8737 				 * (There's an automatic dependency in the opposite direction
8738 				 * anyway, so don't need to add one manually here.)
8739 				 */
8740 				if (!constrs[j].separate)
8741 					addObjectDependency(&tbinfo->dobj,
8742 										constrs[j].dobj.dumpId);
8743 
8744 				/*
8745 				 * If the constraint is inherited, this will be detected later
8746 				 * (in pre-8.4 databases).  We also detect later if the
8747 				 * constraint must be split out from the table definition.
8748 				 */
8749 			}
8750 			PQclear(res);
8751 		}
8752 	}
8753 
8754 	destroyPQExpBuffer(q);
8755 }
8756 
8757 /*
8758  * Test whether a column should be printed as part of table's CREATE TABLE.
8759  * Column number is zero-based.
8760  *
8761  * Normally this is always true, but it's false for dropped columns, as well
8762  * as those that were inherited without any local definition.  (If we print
8763  * such a column it will mistakenly get pg_attribute.attislocal set to true.)
8764  * For partitions, it's always true, because we want the partitions to be
8765  * created independently and ATTACH PARTITION used afterwards.
8766  *
8767  * In binary_upgrade mode, we must print all columns and fix the attislocal/
8768  * attisdropped state later, so as to keep control of the physical column
8769  * order.
8770  *
8771  * This function exists because there are scattered nonobvious places that
8772  * must be kept in sync with this decision.
8773  */
8774 bool
shouldPrintColumn(DumpOptions * dopt,TableInfo * tbinfo,int colno)8775 shouldPrintColumn(DumpOptions *dopt, TableInfo *tbinfo, int colno)
8776 {
8777 	if (dopt->binary_upgrade)
8778 		return true;
8779 	if (tbinfo->attisdropped[colno])
8780 		return false;
8781 	return (tbinfo->attislocal[colno] || tbinfo->ispartition);
8782 }
8783 
8784 
8785 /*
8786  * getTSParsers:
8787  *	  read all text search parsers in the system catalogs and return them
8788  *	  in the TSParserInfo* structure
8789  *
8790  *	numTSParsers is set to the number of parsers read in
8791  */
8792 TSParserInfo *
getTSParsers(Archive * fout,int * numTSParsers)8793 getTSParsers(Archive *fout, int *numTSParsers)
8794 {
8795 	PGresult   *res;
8796 	int			ntups;
8797 	int			i;
8798 	PQExpBuffer query;
8799 	TSParserInfo *prsinfo;
8800 	int			i_tableoid;
8801 	int			i_oid;
8802 	int			i_prsname;
8803 	int			i_prsnamespace;
8804 	int			i_prsstart;
8805 	int			i_prstoken;
8806 	int			i_prsend;
8807 	int			i_prsheadline;
8808 	int			i_prslextype;
8809 
8810 	/* Before 8.3, there is no built-in text search support */
8811 	if (fout->remoteVersion < 80300)
8812 	{
8813 		*numTSParsers = 0;
8814 		return NULL;
8815 	}
8816 
8817 	query = createPQExpBuffer();
8818 
8819 	/*
8820 	 * find all text search objects, including builtin ones; we filter out
8821 	 * system-defined objects at dump-out time.
8822 	 */
8823 
8824 	appendPQExpBufferStr(query, "SELECT tableoid, oid, prsname, prsnamespace, "
8825 						 "prsstart::oid, prstoken::oid, "
8826 						 "prsend::oid, prsheadline::oid, prslextype::oid "
8827 						 "FROM pg_ts_parser");
8828 
8829 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8830 
8831 	ntups = PQntuples(res);
8832 	*numTSParsers = ntups;
8833 
8834 	prsinfo = (TSParserInfo *) pg_malloc(ntups * sizeof(TSParserInfo));
8835 
8836 	i_tableoid = PQfnumber(res, "tableoid");
8837 	i_oid = PQfnumber(res, "oid");
8838 	i_prsname = PQfnumber(res, "prsname");
8839 	i_prsnamespace = PQfnumber(res, "prsnamespace");
8840 	i_prsstart = PQfnumber(res, "prsstart");
8841 	i_prstoken = PQfnumber(res, "prstoken");
8842 	i_prsend = PQfnumber(res, "prsend");
8843 	i_prsheadline = PQfnumber(res, "prsheadline");
8844 	i_prslextype = PQfnumber(res, "prslextype");
8845 
8846 	for (i = 0; i < ntups; i++)
8847 	{
8848 		prsinfo[i].dobj.objType = DO_TSPARSER;
8849 		prsinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8850 		prsinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8851 		AssignDumpId(&prsinfo[i].dobj);
8852 		prsinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_prsname));
8853 		prsinfo[i].dobj.namespace =
8854 			findNamespace(fout,
8855 						  atooid(PQgetvalue(res, i, i_prsnamespace)));
8856 		prsinfo[i].prsstart = atooid(PQgetvalue(res, i, i_prsstart));
8857 		prsinfo[i].prstoken = atooid(PQgetvalue(res, i, i_prstoken));
8858 		prsinfo[i].prsend = atooid(PQgetvalue(res, i, i_prsend));
8859 		prsinfo[i].prsheadline = atooid(PQgetvalue(res, i, i_prsheadline));
8860 		prsinfo[i].prslextype = atooid(PQgetvalue(res, i, i_prslextype));
8861 
8862 		/* Decide whether we want to dump it */
8863 		selectDumpableObject(&(prsinfo[i].dobj), fout);
8864 
8865 		/* Text Search Parsers do not currently have ACLs. */
8866 		prsinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8867 	}
8868 
8869 	PQclear(res);
8870 
8871 	destroyPQExpBuffer(query);
8872 
8873 	return prsinfo;
8874 }
8875 
8876 /*
8877  * getTSDictionaries:
8878  *	  read all text search dictionaries in the system catalogs and return them
8879  *	  in the TSDictInfo* structure
8880  *
8881  *	numTSDicts is set to the number of dictionaries read in
8882  */
8883 TSDictInfo *
getTSDictionaries(Archive * fout,int * numTSDicts)8884 getTSDictionaries(Archive *fout, int *numTSDicts)
8885 {
8886 	PGresult   *res;
8887 	int			ntups;
8888 	int			i;
8889 	PQExpBuffer query;
8890 	TSDictInfo *dictinfo;
8891 	int			i_tableoid;
8892 	int			i_oid;
8893 	int			i_dictname;
8894 	int			i_dictnamespace;
8895 	int			i_rolname;
8896 	int			i_dicttemplate;
8897 	int			i_dictinitoption;
8898 
8899 	/* Before 8.3, there is no built-in text search support */
8900 	if (fout->remoteVersion < 80300)
8901 	{
8902 		*numTSDicts = 0;
8903 		return NULL;
8904 	}
8905 
8906 	query = createPQExpBuffer();
8907 
8908 	appendPQExpBuffer(query, "SELECT tableoid, oid, dictname, "
8909 					  "dictnamespace, (%s dictowner) AS rolname, "
8910 					  "dicttemplate, dictinitoption "
8911 					  "FROM pg_ts_dict",
8912 					  username_subquery);
8913 
8914 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8915 
8916 	ntups = PQntuples(res);
8917 	*numTSDicts = ntups;
8918 
8919 	dictinfo = (TSDictInfo *) pg_malloc(ntups * sizeof(TSDictInfo));
8920 
8921 	i_tableoid = PQfnumber(res, "tableoid");
8922 	i_oid = PQfnumber(res, "oid");
8923 	i_dictname = PQfnumber(res, "dictname");
8924 	i_dictnamespace = PQfnumber(res, "dictnamespace");
8925 	i_rolname = PQfnumber(res, "rolname");
8926 	i_dictinitoption = PQfnumber(res, "dictinitoption");
8927 	i_dicttemplate = PQfnumber(res, "dicttemplate");
8928 
8929 	for (i = 0; i < ntups; i++)
8930 	{
8931 		dictinfo[i].dobj.objType = DO_TSDICT;
8932 		dictinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
8933 		dictinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
8934 		AssignDumpId(&dictinfo[i].dobj);
8935 		dictinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dictname));
8936 		dictinfo[i].dobj.namespace =
8937 			findNamespace(fout,
8938 						  atooid(PQgetvalue(res, i, i_dictnamespace)));
8939 		dictinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
8940 		dictinfo[i].dicttemplate = atooid(PQgetvalue(res, i, i_dicttemplate));
8941 		if (PQgetisnull(res, i, i_dictinitoption))
8942 			dictinfo[i].dictinitoption = NULL;
8943 		else
8944 			dictinfo[i].dictinitoption = pg_strdup(PQgetvalue(res, i, i_dictinitoption));
8945 
8946 		/* Decide whether we want to dump it */
8947 		selectDumpableObject(&(dictinfo[i].dobj), fout);
8948 
8949 		/* Text Search Dictionaries do not currently have ACLs. */
8950 		dictinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
8951 	}
8952 
8953 	PQclear(res);
8954 
8955 	destroyPQExpBuffer(query);
8956 
8957 	return dictinfo;
8958 }
8959 
8960 /*
8961  * getTSTemplates:
8962  *	  read all text search templates in the system catalogs and return them
8963  *	  in the TSTemplateInfo* structure
8964  *
8965  *	numTSTemplates is set to the number of templates read in
8966  */
8967 TSTemplateInfo *
getTSTemplates(Archive * fout,int * numTSTemplates)8968 getTSTemplates(Archive *fout, int *numTSTemplates)
8969 {
8970 	PGresult   *res;
8971 	int			ntups;
8972 	int			i;
8973 	PQExpBuffer query;
8974 	TSTemplateInfo *tmplinfo;
8975 	int			i_tableoid;
8976 	int			i_oid;
8977 	int			i_tmplname;
8978 	int			i_tmplnamespace;
8979 	int			i_tmplinit;
8980 	int			i_tmpllexize;
8981 
8982 	/* Before 8.3, there is no built-in text search support */
8983 	if (fout->remoteVersion < 80300)
8984 	{
8985 		*numTSTemplates = 0;
8986 		return NULL;
8987 	}
8988 
8989 	query = createPQExpBuffer();
8990 
8991 	appendPQExpBufferStr(query, "SELECT tableoid, oid, tmplname, "
8992 						 "tmplnamespace, tmplinit::oid, tmpllexize::oid "
8993 						 "FROM pg_ts_template");
8994 
8995 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
8996 
8997 	ntups = PQntuples(res);
8998 	*numTSTemplates = ntups;
8999 
9000 	tmplinfo = (TSTemplateInfo *) pg_malloc(ntups * sizeof(TSTemplateInfo));
9001 
9002 	i_tableoid = PQfnumber(res, "tableoid");
9003 	i_oid = PQfnumber(res, "oid");
9004 	i_tmplname = PQfnumber(res, "tmplname");
9005 	i_tmplnamespace = PQfnumber(res, "tmplnamespace");
9006 	i_tmplinit = PQfnumber(res, "tmplinit");
9007 	i_tmpllexize = PQfnumber(res, "tmpllexize");
9008 
9009 	for (i = 0; i < ntups; i++)
9010 	{
9011 		tmplinfo[i].dobj.objType = DO_TSTEMPLATE;
9012 		tmplinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9013 		tmplinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9014 		AssignDumpId(&tmplinfo[i].dobj);
9015 		tmplinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_tmplname));
9016 		tmplinfo[i].dobj.namespace =
9017 			findNamespace(fout,
9018 						  atooid(PQgetvalue(res, i, i_tmplnamespace)));
9019 		tmplinfo[i].tmplinit = atooid(PQgetvalue(res, i, i_tmplinit));
9020 		tmplinfo[i].tmpllexize = atooid(PQgetvalue(res, i, i_tmpllexize));
9021 
9022 		/* Decide whether we want to dump it */
9023 		selectDumpableObject(&(tmplinfo[i].dobj), fout);
9024 
9025 		/* Text Search Templates do not currently have ACLs. */
9026 		tmplinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
9027 	}
9028 
9029 	PQclear(res);
9030 
9031 	destroyPQExpBuffer(query);
9032 
9033 	return tmplinfo;
9034 }
9035 
9036 /*
9037  * getTSConfigurations:
9038  *	  read all text search configurations in the system catalogs and return
9039  *	  them in the TSConfigInfo* structure
9040  *
9041  *	numTSConfigs is set to the number of configurations read in
9042  */
9043 TSConfigInfo *
getTSConfigurations(Archive * fout,int * numTSConfigs)9044 getTSConfigurations(Archive *fout, int *numTSConfigs)
9045 {
9046 	PGresult   *res;
9047 	int			ntups;
9048 	int			i;
9049 	PQExpBuffer query;
9050 	TSConfigInfo *cfginfo;
9051 	int			i_tableoid;
9052 	int			i_oid;
9053 	int			i_cfgname;
9054 	int			i_cfgnamespace;
9055 	int			i_rolname;
9056 	int			i_cfgparser;
9057 
9058 	/* Before 8.3, there is no built-in text search support */
9059 	if (fout->remoteVersion < 80300)
9060 	{
9061 		*numTSConfigs = 0;
9062 		return NULL;
9063 	}
9064 
9065 	query = createPQExpBuffer();
9066 
9067 	appendPQExpBuffer(query, "SELECT tableoid, oid, cfgname, "
9068 					  "cfgnamespace, (%s cfgowner) AS rolname, cfgparser "
9069 					  "FROM pg_ts_config",
9070 					  username_subquery);
9071 
9072 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9073 
9074 	ntups = PQntuples(res);
9075 	*numTSConfigs = ntups;
9076 
9077 	cfginfo = (TSConfigInfo *) pg_malloc(ntups * sizeof(TSConfigInfo));
9078 
9079 	i_tableoid = PQfnumber(res, "tableoid");
9080 	i_oid = PQfnumber(res, "oid");
9081 	i_cfgname = PQfnumber(res, "cfgname");
9082 	i_cfgnamespace = PQfnumber(res, "cfgnamespace");
9083 	i_rolname = PQfnumber(res, "rolname");
9084 	i_cfgparser = PQfnumber(res, "cfgparser");
9085 
9086 	for (i = 0; i < ntups; i++)
9087 	{
9088 		cfginfo[i].dobj.objType = DO_TSCONFIG;
9089 		cfginfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9090 		cfginfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9091 		AssignDumpId(&cfginfo[i].dobj);
9092 		cfginfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_cfgname));
9093 		cfginfo[i].dobj.namespace =
9094 			findNamespace(fout,
9095 						  atooid(PQgetvalue(res, i, i_cfgnamespace)));
9096 		cfginfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
9097 		cfginfo[i].cfgparser = atooid(PQgetvalue(res, i, i_cfgparser));
9098 
9099 		/* Decide whether we want to dump it */
9100 		selectDumpableObject(&(cfginfo[i].dobj), fout);
9101 
9102 		/* Text Search Configurations do not currently have ACLs. */
9103 		cfginfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
9104 	}
9105 
9106 	PQclear(res);
9107 
9108 	destroyPQExpBuffer(query);
9109 
9110 	return cfginfo;
9111 }
9112 
9113 /*
9114  * getForeignDataWrappers:
9115  *	  read all foreign-data wrappers in the system catalogs and return
9116  *	  them in the FdwInfo* structure
9117  *
9118  *	numForeignDataWrappers is set to the number of fdws read in
9119  */
9120 FdwInfo *
getForeignDataWrappers(Archive * fout,int * numForeignDataWrappers)9121 getForeignDataWrappers(Archive *fout, int *numForeignDataWrappers)
9122 {
9123 	DumpOptions *dopt = fout->dopt;
9124 	PGresult   *res;
9125 	int			ntups;
9126 	int			i;
9127 	PQExpBuffer query;
9128 	FdwInfo    *fdwinfo;
9129 	int			i_tableoid;
9130 	int			i_oid;
9131 	int			i_fdwname;
9132 	int			i_rolname;
9133 	int			i_fdwhandler;
9134 	int			i_fdwvalidator;
9135 	int			i_fdwacl;
9136 	int			i_rfdwacl;
9137 	int			i_initfdwacl;
9138 	int			i_initrfdwacl;
9139 	int			i_fdwoptions;
9140 
9141 	/* Before 8.4, there are no foreign-data wrappers */
9142 	if (fout->remoteVersion < 80400)
9143 	{
9144 		*numForeignDataWrappers = 0;
9145 		return NULL;
9146 	}
9147 
9148 	query = createPQExpBuffer();
9149 
9150 	if (fout->remoteVersion >= 90600)
9151 	{
9152 		PQExpBuffer acl_subquery = createPQExpBuffer();
9153 		PQExpBuffer racl_subquery = createPQExpBuffer();
9154 		PQExpBuffer initacl_subquery = createPQExpBuffer();
9155 		PQExpBuffer initracl_subquery = createPQExpBuffer();
9156 
9157 		buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
9158 						initracl_subquery, "f.fdwacl", "f.fdwowner", "'F'",
9159 						dopt->binary_upgrade);
9160 
9161 		appendPQExpBuffer(query, "SELECT f.tableoid, f.oid, f.fdwname, "
9162 						  "(%s f.fdwowner) AS rolname, "
9163 						  "f.fdwhandler::pg_catalog.regproc, "
9164 						  "f.fdwvalidator::pg_catalog.regproc, "
9165 						  "%s AS fdwacl, "
9166 						  "%s AS rfdwacl, "
9167 						  "%s AS initfdwacl, "
9168 						  "%s AS initrfdwacl, "
9169 						  "array_to_string(ARRAY("
9170 						  "SELECT quote_ident(option_name) || ' ' || "
9171 						  "quote_literal(option_value) "
9172 						  "FROM pg_options_to_table(f.fdwoptions) "
9173 						  "ORDER BY option_name"
9174 						  "), E',\n    ') AS fdwoptions "
9175 						  "FROM pg_foreign_data_wrapper f "
9176 						  "LEFT JOIN pg_init_privs pip ON "
9177 						  "(f.oid = pip.objoid "
9178 						  "AND pip.classoid = 'pg_foreign_data_wrapper'::regclass "
9179 						  "AND pip.objsubid = 0) ",
9180 						  username_subquery,
9181 						  acl_subquery->data,
9182 						  racl_subquery->data,
9183 						  initacl_subquery->data,
9184 						  initracl_subquery->data);
9185 
9186 		destroyPQExpBuffer(acl_subquery);
9187 		destroyPQExpBuffer(racl_subquery);
9188 		destroyPQExpBuffer(initacl_subquery);
9189 		destroyPQExpBuffer(initracl_subquery);
9190 	}
9191 	else if (fout->remoteVersion >= 90100)
9192 	{
9193 		appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
9194 						  "(%s fdwowner) AS rolname, "
9195 						  "fdwhandler::pg_catalog.regproc, "
9196 						  "fdwvalidator::pg_catalog.regproc, fdwacl, "
9197 						  "NULL as rfdwacl, "
9198 						  "NULL as initfdwacl, NULL AS initrfdwacl, "
9199 						  "array_to_string(ARRAY("
9200 						  "SELECT quote_ident(option_name) || ' ' || "
9201 						  "quote_literal(option_value) "
9202 						  "FROM pg_options_to_table(fdwoptions) "
9203 						  "ORDER BY option_name"
9204 						  "), E',\n    ') AS fdwoptions "
9205 						  "FROM pg_foreign_data_wrapper",
9206 						  username_subquery);
9207 	}
9208 	else
9209 	{
9210 		appendPQExpBuffer(query, "SELECT tableoid, oid, fdwname, "
9211 						  "(%s fdwowner) AS rolname, "
9212 						  "'-' AS fdwhandler, "
9213 						  "fdwvalidator::pg_catalog.regproc, fdwacl, "
9214 						  "NULL as rfdwacl, "
9215 						  "NULL as initfdwacl, NULL AS initrfdwacl, "
9216 						  "array_to_string(ARRAY("
9217 						  "SELECT quote_ident(option_name) || ' ' || "
9218 						  "quote_literal(option_value) "
9219 						  "FROM pg_options_to_table(fdwoptions) "
9220 						  "ORDER BY option_name"
9221 						  "), E',\n    ') AS fdwoptions "
9222 						  "FROM pg_foreign_data_wrapper",
9223 						  username_subquery);
9224 	}
9225 
9226 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9227 
9228 	ntups = PQntuples(res);
9229 	*numForeignDataWrappers = ntups;
9230 
9231 	fdwinfo = (FdwInfo *) pg_malloc(ntups * sizeof(FdwInfo));
9232 
9233 	i_tableoid = PQfnumber(res, "tableoid");
9234 	i_oid = PQfnumber(res, "oid");
9235 	i_fdwname = PQfnumber(res, "fdwname");
9236 	i_rolname = PQfnumber(res, "rolname");
9237 	i_fdwhandler = PQfnumber(res, "fdwhandler");
9238 	i_fdwvalidator = PQfnumber(res, "fdwvalidator");
9239 	i_fdwacl = PQfnumber(res, "fdwacl");
9240 	i_rfdwacl = PQfnumber(res, "rfdwacl");
9241 	i_initfdwacl = PQfnumber(res, "initfdwacl");
9242 	i_initrfdwacl = PQfnumber(res, "initrfdwacl");
9243 	i_fdwoptions = PQfnumber(res, "fdwoptions");
9244 
9245 	for (i = 0; i < ntups; i++)
9246 	{
9247 		fdwinfo[i].dobj.objType = DO_FDW;
9248 		fdwinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9249 		fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9250 		AssignDumpId(&fdwinfo[i].dobj);
9251 		fdwinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_fdwname));
9252 		fdwinfo[i].dobj.namespace = NULL;
9253 		fdwinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
9254 		fdwinfo[i].fdwhandler = pg_strdup(PQgetvalue(res, i, i_fdwhandler));
9255 		fdwinfo[i].fdwvalidator = pg_strdup(PQgetvalue(res, i, i_fdwvalidator));
9256 		fdwinfo[i].fdwoptions = pg_strdup(PQgetvalue(res, i, i_fdwoptions));
9257 		fdwinfo[i].fdwacl = pg_strdup(PQgetvalue(res, i, i_fdwacl));
9258 		fdwinfo[i].rfdwacl = pg_strdup(PQgetvalue(res, i, i_rfdwacl));
9259 		fdwinfo[i].initfdwacl = pg_strdup(PQgetvalue(res, i, i_initfdwacl));
9260 		fdwinfo[i].initrfdwacl = pg_strdup(PQgetvalue(res, i, i_initrfdwacl));
9261 
9262 		/* Decide whether we want to dump it */
9263 		selectDumpableObject(&(fdwinfo[i].dobj), fout);
9264 
9265 		/* Do not try to dump ACL if no ACL exists. */
9266 		if (PQgetisnull(res, i, i_fdwacl) && PQgetisnull(res, i, i_rfdwacl) &&
9267 			PQgetisnull(res, i, i_initfdwacl) &&
9268 			PQgetisnull(res, i, i_initrfdwacl))
9269 			fdwinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
9270 	}
9271 
9272 	PQclear(res);
9273 
9274 	destroyPQExpBuffer(query);
9275 
9276 	return fdwinfo;
9277 }
9278 
9279 /*
9280  * getForeignServers:
9281  *	  read all foreign servers in the system catalogs and return
9282  *	  them in the ForeignServerInfo * structure
9283  *
9284  *	numForeignServers is set to the number of servers read in
9285  */
9286 ForeignServerInfo *
getForeignServers(Archive * fout,int * numForeignServers)9287 getForeignServers(Archive *fout, int *numForeignServers)
9288 {
9289 	DumpOptions *dopt = fout->dopt;
9290 	PGresult   *res;
9291 	int			ntups;
9292 	int			i;
9293 	PQExpBuffer query;
9294 	ForeignServerInfo *srvinfo;
9295 	int			i_tableoid;
9296 	int			i_oid;
9297 	int			i_srvname;
9298 	int			i_rolname;
9299 	int			i_srvfdw;
9300 	int			i_srvtype;
9301 	int			i_srvversion;
9302 	int			i_srvacl;
9303 	int			i_rsrvacl;
9304 	int			i_initsrvacl;
9305 	int			i_initrsrvacl;
9306 	int			i_srvoptions;
9307 
9308 	/* Before 8.4, there are no foreign servers */
9309 	if (fout->remoteVersion < 80400)
9310 	{
9311 		*numForeignServers = 0;
9312 		return NULL;
9313 	}
9314 
9315 	query = createPQExpBuffer();
9316 
9317 	if (fout->remoteVersion >= 90600)
9318 	{
9319 		PQExpBuffer acl_subquery = createPQExpBuffer();
9320 		PQExpBuffer racl_subquery = createPQExpBuffer();
9321 		PQExpBuffer initacl_subquery = createPQExpBuffer();
9322 		PQExpBuffer initracl_subquery = createPQExpBuffer();
9323 
9324 		buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
9325 						initracl_subquery, "f.srvacl", "f.srvowner", "'S'",
9326 						dopt->binary_upgrade);
9327 
9328 		appendPQExpBuffer(query, "SELECT f.tableoid, f.oid, f.srvname, "
9329 						  "(%s f.srvowner) AS rolname, "
9330 						  "f.srvfdw, f.srvtype, f.srvversion, "
9331 						  "%s AS srvacl, "
9332 						  "%s AS rsrvacl, "
9333 						  "%s AS initsrvacl, "
9334 						  "%s AS initrsrvacl, "
9335 						  "array_to_string(ARRAY("
9336 						  "SELECT quote_ident(option_name) || ' ' || "
9337 						  "quote_literal(option_value) "
9338 						  "FROM pg_options_to_table(f.srvoptions) "
9339 						  "ORDER BY option_name"
9340 						  "), E',\n    ') AS srvoptions "
9341 						  "FROM pg_foreign_server f "
9342 						  "LEFT JOIN pg_init_privs pip "
9343 						  "ON (f.oid = pip.objoid "
9344 						  "AND pip.classoid = 'pg_foreign_server'::regclass "
9345 						  "AND pip.objsubid = 0) ",
9346 						  username_subquery,
9347 						  acl_subquery->data,
9348 						  racl_subquery->data,
9349 						  initacl_subquery->data,
9350 						  initracl_subquery->data);
9351 
9352 		destroyPQExpBuffer(acl_subquery);
9353 		destroyPQExpBuffer(racl_subquery);
9354 		destroyPQExpBuffer(initacl_subquery);
9355 		destroyPQExpBuffer(initracl_subquery);
9356 	}
9357 	else
9358 	{
9359 		appendPQExpBuffer(query, "SELECT tableoid, oid, srvname, "
9360 						  "(%s srvowner) AS rolname, "
9361 						  "srvfdw, srvtype, srvversion, srvacl, "
9362 						  "NULL AS rsrvacl, "
9363 						  "NULL AS initsrvacl, NULL AS initrsrvacl, "
9364 						  "array_to_string(ARRAY("
9365 						  "SELECT quote_ident(option_name) || ' ' || "
9366 						  "quote_literal(option_value) "
9367 						  "FROM pg_options_to_table(srvoptions) "
9368 						  "ORDER BY option_name"
9369 						  "), E',\n    ') AS srvoptions "
9370 						  "FROM pg_foreign_server",
9371 						  username_subquery);
9372 	}
9373 
9374 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9375 
9376 	ntups = PQntuples(res);
9377 	*numForeignServers = ntups;
9378 
9379 	srvinfo = (ForeignServerInfo *) pg_malloc(ntups * sizeof(ForeignServerInfo));
9380 
9381 	i_tableoid = PQfnumber(res, "tableoid");
9382 	i_oid = PQfnumber(res, "oid");
9383 	i_srvname = PQfnumber(res, "srvname");
9384 	i_rolname = PQfnumber(res, "rolname");
9385 	i_srvfdw = PQfnumber(res, "srvfdw");
9386 	i_srvtype = PQfnumber(res, "srvtype");
9387 	i_srvversion = PQfnumber(res, "srvversion");
9388 	i_srvacl = PQfnumber(res, "srvacl");
9389 	i_rsrvacl = PQfnumber(res, "rsrvacl");
9390 	i_initsrvacl = PQfnumber(res, "initsrvacl");
9391 	i_initrsrvacl = PQfnumber(res, "initrsrvacl");
9392 	i_srvoptions = PQfnumber(res, "srvoptions");
9393 
9394 	for (i = 0; i < ntups; i++)
9395 	{
9396 		srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
9397 		srvinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9398 		srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9399 		AssignDumpId(&srvinfo[i].dobj);
9400 		srvinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_srvname));
9401 		srvinfo[i].dobj.namespace = NULL;
9402 		srvinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
9403 		srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
9404 		srvinfo[i].srvtype = pg_strdup(PQgetvalue(res, i, i_srvtype));
9405 		srvinfo[i].srvversion = pg_strdup(PQgetvalue(res, i, i_srvversion));
9406 		srvinfo[i].srvoptions = pg_strdup(PQgetvalue(res, i, i_srvoptions));
9407 		srvinfo[i].srvacl = pg_strdup(PQgetvalue(res, i, i_srvacl));
9408 		srvinfo[i].rsrvacl = pg_strdup(PQgetvalue(res, i, i_rsrvacl));
9409 		srvinfo[i].initsrvacl = pg_strdup(PQgetvalue(res, i, i_initsrvacl));
9410 		srvinfo[i].initrsrvacl = pg_strdup(PQgetvalue(res, i, i_initrsrvacl));
9411 
9412 		/* Decide whether we want to dump it */
9413 		selectDumpableObject(&(srvinfo[i].dobj), fout);
9414 
9415 		/* Do not try to dump ACL if no ACL exists. */
9416 		if (PQgetisnull(res, i, i_srvacl) && PQgetisnull(res, i, i_rsrvacl) &&
9417 			PQgetisnull(res, i, i_initsrvacl) &&
9418 			PQgetisnull(res, i, i_initrsrvacl))
9419 			srvinfo[i].dobj.dump &= ~DUMP_COMPONENT_ACL;
9420 	}
9421 
9422 	PQclear(res);
9423 
9424 	destroyPQExpBuffer(query);
9425 
9426 	return srvinfo;
9427 }
9428 
9429 /*
9430  * getDefaultACLs:
9431  *	  read all default ACL information in the system catalogs and return
9432  *	  them in the DefaultACLInfo structure
9433  *
9434  *	numDefaultACLs is set to the number of ACLs read in
9435  */
9436 DefaultACLInfo *
getDefaultACLs(Archive * fout,int * numDefaultACLs)9437 getDefaultACLs(Archive *fout, int *numDefaultACLs)
9438 {
9439 	DumpOptions *dopt = fout->dopt;
9440 	DefaultACLInfo *daclinfo;
9441 	PQExpBuffer query;
9442 	PGresult   *res;
9443 	int			i_oid;
9444 	int			i_tableoid;
9445 	int			i_defaclrole;
9446 	int			i_defaclnamespace;
9447 	int			i_defaclobjtype;
9448 	int			i_defaclacl;
9449 	int			i_rdefaclacl;
9450 	int			i_initdefaclacl;
9451 	int			i_initrdefaclacl;
9452 	int			i,
9453 				ntups;
9454 
9455 	if (fout->remoteVersion < 90000)
9456 	{
9457 		*numDefaultACLs = 0;
9458 		return NULL;
9459 	}
9460 
9461 	query = createPQExpBuffer();
9462 
9463 	if (fout->remoteVersion >= 90600)
9464 	{
9465 		PQExpBuffer acl_subquery = createPQExpBuffer();
9466 		PQExpBuffer racl_subquery = createPQExpBuffer();
9467 		PQExpBuffer initacl_subquery = createPQExpBuffer();
9468 		PQExpBuffer initracl_subquery = createPQExpBuffer();
9469 
9470 		/*
9471 		 * Global entries (with defaclnamespace=0) replace the hard-wired
9472 		 * default ACL for their object type.  We should dump them as deltas
9473 		 * from the default ACL, since that will be used as a starting point
9474 		 * for interpreting the ALTER DEFAULT PRIVILEGES commands.  On the
9475 		 * other hand, non-global entries can only add privileges not revoke
9476 		 * them.  We must dump those as-is (i.e., as deltas from an empty
9477 		 * ACL).  We implement that by passing NULL as the object type for
9478 		 * acldefault(), which works because acldefault() is STRICT.
9479 		 *
9480 		 * We can use defaclobjtype as the object type for acldefault(),
9481 		 * except for the case of 'S' (DEFACLOBJ_SEQUENCE) which must be
9482 		 * converted to 's'.
9483 		 */
9484 		buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
9485 						initracl_subquery, "defaclacl", "defaclrole",
9486 						"CASE WHEN defaclnamespace = 0 THEN"
9487 						"	  CASE WHEN defaclobjtype = 'S' THEN 's'::\"char\""
9488 						"	  ELSE defaclobjtype END "
9489 						"ELSE NULL END",
9490 						dopt->binary_upgrade);
9491 
9492 		appendPQExpBuffer(query, "SELECT d.oid, d.tableoid, "
9493 						  "(%s d.defaclrole) AS defaclrole, "
9494 						  "d.defaclnamespace, "
9495 						  "d.defaclobjtype, "
9496 						  "%s AS defaclacl, "
9497 						  "%s AS rdefaclacl, "
9498 						  "%s AS initdefaclacl, "
9499 						  "%s AS initrdefaclacl "
9500 						  "FROM pg_default_acl d "
9501 						  "LEFT JOIN pg_init_privs pip ON "
9502 						  "(d.oid = pip.objoid "
9503 						  "AND pip.classoid = 'pg_default_acl'::regclass "
9504 						  "AND pip.objsubid = 0) ",
9505 						  username_subquery,
9506 						  acl_subquery->data,
9507 						  racl_subquery->data,
9508 						  initacl_subquery->data,
9509 						  initracl_subquery->data);
9510 
9511 		destroyPQExpBuffer(acl_subquery);
9512 		destroyPQExpBuffer(racl_subquery);
9513 		destroyPQExpBuffer(initacl_subquery);
9514 		destroyPQExpBuffer(initracl_subquery);
9515 	}
9516 	else
9517 	{
9518 		appendPQExpBuffer(query, "SELECT oid, tableoid, "
9519 						  "(%s defaclrole) AS defaclrole, "
9520 						  "defaclnamespace, "
9521 						  "defaclobjtype, "
9522 						  "defaclacl, "
9523 						  "NULL AS rdefaclacl, "
9524 						  "NULL AS initdefaclacl, "
9525 						  "NULL AS initrdefaclacl "
9526 						  "FROM pg_default_acl",
9527 						  username_subquery);
9528 	}
9529 
9530 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9531 
9532 	ntups = PQntuples(res);
9533 	*numDefaultACLs = ntups;
9534 
9535 	daclinfo = (DefaultACLInfo *) pg_malloc(ntups * sizeof(DefaultACLInfo));
9536 
9537 	i_oid = PQfnumber(res, "oid");
9538 	i_tableoid = PQfnumber(res, "tableoid");
9539 	i_defaclrole = PQfnumber(res, "defaclrole");
9540 	i_defaclnamespace = PQfnumber(res, "defaclnamespace");
9541 	i_defaclobjtype = PQfnumber(res, "defaclobjtype");
9542 	i_defaclacl = PQfnumber(res, "defaclacl");
9543 	i_rdefaclacl = PQfnumber(res, "rdefaclacl");
9544 	i_initdefaclacl = PQfnumber(res, "initdefaclacl");
9545 	i_initrdefaclacl = PQfnumber(res, "initrdefaclacl");
9546 
9547 	for (i = 0; i < ntups; i++)
9548 	{
9549 		Oid			nspid = atooid(PQgetvalue(res, i, i_defaclnamespace));
9550 
9551 		daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
9552 		daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
9553 		daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
9554 		AssignDumpId(&daclinfo[i].dobj);
9555 		/* cheesy ... is it worth coming up with a better object name? */
9556 		daclinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_defaclobjtype));
9557 
9558 		if (nspid != InvalidOid)
9559 			daclinfo[i].dobj.namespace = findNamespace(fout, nspid);
9560 		else
9561 			daclinfo[i].dobj.namespace = NULL;
9562 
9563 		daclinfo[i].defaclrole = pg_strdup(PQgetvalue(res, i, i_defaclrole));
9564 		daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
9565 		daclinfo[i].defaclacl = pg_strdup(PQgetvalue(res, i, i_defaclacl));
9566 		daclinfo[i].rdefaclacl = pg_strdup(PQgetvalue(res, i, i_rdefaclacl));
9567 		daclinfo[i].initdefaclacl = pg_strdup(PQgetvalue(res, i, i_initdefaclacl));
9568 		daclinfo[i].initrdefaclacl = pg_strdup(PQgetvalue(res, i, i_initrdefaclacl));
9569 
9570 		/* Decide whether we want to dump it */
9571 		selectDumpableDefaultACL(&(daclinfo[i]), dopt);
9572 	}
9573 
9574 	PQclear(res);
9575 
9576 	destroyPQExpBuffer(query);
9577 
9578 	return daclinfo;
9579 }
9580 
9581 /*
9582  * dumpComment --
9583  *
9584  * This routine is used to dump any comments associated with the
9585  * object handed to this routine. The routine takes the object type
9586  * and object name (ready to print, except for schema decoration), plus
9587  * the namespace and owner of the object (for labeling the ArchiveEntry),
9588  * plus catalog ID and subid which are the lookup key for pg_description,
9589  * plus the dump ID for the object (for setting a dependency).
9590  * If a matching pg_description entry is found, it is dumped.
9591  *
9592  * Note: in some cases, such as comments for triggers and rules, the "type"
9593  * string really looks like, e.g., "TRIGGER name ON".  This is a bit of a hack
9594  * but it doesn't seem worth complicating the API for all callers to make
9595  * it cleaner.
9596  *
9597  * Note: although this routine takes a dumpId for dependency purposes,
9598  * that purpose is just to mark the dependency in the emitted dump file
9599  * for possible future use by pg_restore.  We do NOT use it for determining
9600  * ordering of the comment in the dump file, because this routine is called
9601  * after dependency sorting occurs.  This routine should be called just after
9602  * calling ArchiveEntry() for the specified object.
9603  */
9604 static void
dumpComment(Archive * fout,const char * type,const char * name,const char * namespace,const char * owner,CatalogId catalogId,int subid,DumpId dumpId)9605 dumpComment(Archive *fout, const char *type, const char *name,
9606 			const char *namespace, const char *owner,
9607 			CatalogId catalogId, int subid, DumpId dumpId)
9608 {
9609 	DumpOptions *dopt = fout->dopt;
9610 	CommentItem *comments;
9611 	int			ncomments;
9612 
9613 	/* do nothing, if --no-comments is supplied */
9614 	if (dopt->no_comments)
9615 		return;
9616 
9617 	/* Comments are schema not data ... except blob comments are data */
9618 	if (strcmp(type, "LARGE OBJECT") != 0)
9619 	{
9620 		if (dopt->dataOnly)
9621 			return;
9622 	}
9623 	else
9624 	{
9625 		/* We do dump blob comments in binary-upgrade mode */
9626 		if (dopt->schemaOnly && !dopt->binary_upgrade)
9627 			return;
9628 	}
9629 
9630 	/* Search for comments associated with catalogId, using table */
9631 	ncomments = findComments(fout, catalogId.tableoid, catalogId.oid,
9632 							 &comments);
9633 
9634 	/* Is there one matching the subid? */
9635 	while (ncomments > 0)
9636 	{
9637 		if (comments->objsubid == subid)
9638 			break;
9639 		comments++;
9640 		ncomments--;
9641 	}
9642 
9643 	/* If a comment exists, build COMMENT ON statement */
9644 	if (ncomments > 0)
9645 	{
9646 		PQExpBuffer query = createPQExpBuffer();
9647 		PQExpBuffer tag = createPQExpBuffer();
9648 
9649 		appendPQExpBuffer(query, "COMMENT ON %s ", type);
9650 		if (namespace && *namespace)
9651 			appendPQExpBuffer(query, "%s.", fmtId(namespace));
9652 		appendPQExpBuffer(query, "%s IS ", name);
9653 		appendStringLiteralAH(query, comments->descr, fout);
9654 		appendPQExpBufferStr(query, ";\n");
9655 
9656 		appendPQExpBuffer(tag, "%s %s", type, name);
9657 
9658 		/*
9659 		 * We mark comments as SECTION_NONE because they really belong in the
9660 		 * same section as their parent, whether that is pre-data or
9661 		 * post-data.
9662 		 */
9663 		ArchiveEntry(fout, nilCatalogId, createDumpId(),
9664 					 tag->data, namespace, NULL, owner,
9665 					 false, "COMMENT", SECTION_NONE,
9666 					 query->data, "", NULL,
9667 					 &(dumpId), 1,
9668 					 NULL, NULL);
9669 
9670 		destroyPQExpBuffer(query);
9671 		destroyPQExpBuffer(tag);
9672 	}
9673 }
9674 
9675 /*
9676  * dumpTableComment --
9677  *
9678  * As above, but dump comments for both the specified table (or view)
9679  * and its columns.
9680  */
9681 static void
dumpTableComment(Archive * fout,TableInfo * tbinfo,const char * reltypename)9682 dumpTableComment(Archive *fout, TableInfo *tbinfo,
9683 				 const char *reltypename)
9684 {
9685 	DumpOptions *dopt = fout->dopt;
9686 	CommentItem *comments;
9687 	int			ncomments;
9688 	PQExpBuffer query;
9689 	PQExpBuffer tag;
9690 
9691 	/* do nothing, if --no-comments is supplied */
9692 	if (dopt->no_comments)
9693 		return;
9694 
9695 	/* Comments are SCHEMA not data */
9696 	if (dopt->dataOnly)
9697 		return;
9698 
9699 	/* Search for comments associated with relation, using table */
9700 	ncomments = findComments(fout,
9701 							 tbinfo->dobj.catId.tableoid,
9702 							 tbinfo->dobj.catId.oid,
9703 							 &comments);
9704 
9705 	/* If comments exist, build COMMENT ON statements */
9706 	if (ncomments <= 0)
9707 		return;
9708 
9709 	query = createPQExpBuffer();
9710 	tag = createPQExpBuffer();
9711 
9712 	while (ncomments > 0)
9713 	{
9714 		const char *descr = comments->descr;
9715 		int			objsubid = comments->objsubid;
9716 
9717 		if (objsubid == 0)
9718 		{
9719 			resetPQExpBuffer(tag);
9720 			appendPQExpBuffer(tag, "%s %s", reltypename,
9721 							  fmtId(tbinfo->dobj.name));
9722 
9723 			resetPQExpBuffer(query);
9724 			appendPQExpBuffer(query, "COMMENT ON %s %s IS ", reltypename,
9725 							  fmtQualifiedDumpable(tbinfo));
9726 			appendStringLiteralAH(query, descr, fout);
9727 			appendPQExpBufferStr(query, ";\n");
9728 
9729 			ArchiveEntry(fout, nilCatalogId, createDumpId(),
9730 						 tag->data,
9731 						 tbinfo->dobj.namespace->dobj.name,
9732 						 NULL, tbinfo->rolname,
9733 						 false, "COMMENT", SECTION_NONE,
9734 						 query->data, "", NULL,
9735 						 &(tbinfo->dobj.dumpId), 1,
9736 						 NULL, NULL);
9737 		}
9738 		else if (objsubid > 0 && objsubid <= tbinfo->numatts)
9739 		{
9740 			resetPQExpBuffer(tag);
9741 			appendPQExpBuffer(tag, "COLUMN %s.",
9742 							  fmtId(tbinfo->dobj.name));
9743 			appendPQExpBufferStr(tag, fmtId(tbinfo->attnames[objsubid - 1]));
9744 
9745 			resetPQExpBuffer(query);
9746 			appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
9747 							  fmtQualifiedDumpable(tbinfo));
9748 			appendPQExpBuffer(query, "%s IS ",
9749 							  fmtId(tbinfo->attnames[objsubid - 1]));
9750 			appendStringLiteralAH(query, descr, fout);
9751 			appendPQExpBufferStr(query, ";\n");
9752 
9753 			ArchiveEntry(fout, nilCatalogId, createDumpId(),
9754 						 tag->data,
9755 						 tbinfo->dobj.namespace->dobj.name,
9756 						 NULL, tbinfo->rolname,
9757 						 false, "COMMENT", SECTION_NONE,
9758 						 query->data, "", NULL,
9759 						 &(tbinfo->dobj.dumpId), 1,
9760 						 NULL, NULL);
9761 		}
9762 
9763 		comments++;
9764 		ncomments--;
9765 	}
9766 
9767 	destroyPQExpBuffer(query);
9768 	destroyPQExpBuffer(tag);
9769 }
9770 
9771 /*
9772  * findComments --
9773  *
9774  * Find the comment(s), if any, associated with the given object.  All the
9775  * objsubid values associated with the given classoid/objoid are found with
9776  * one search.
9777  */
9778 static int
findComments(Archive * fout,Oid classoid,Oid objoid,CommentItem ** items)9779 findComments(Archive *fout, Oid classoid, Oid objoid,
9780 			 CommentItem **items)
9781 {
9782 	/* static storage for table of comments */
9783 	static CommentItem *comments = NULL;
9784 	static int	ncomments = -1;
9785 
9786 	CommentItem *middle = NULL;
9787 	CommentItem *low;
9788 	CommentItem *high;
9789 	int			nmatch;
9790 
9791 	/* Get comments if we didn't already */
9792 	if (ncomments < 0)
9793 		ncomments = collectComments(fout, &comments);
9794 
9795 	/*
9796 	 * Do binary search to find some item matching the object.
9797 	 */
9798 	low = &comments[0];
9799 	high = &comments[ncomments - 1];
9800 	while (low <= high)
9801 	{
9802 		middle = low + (high - low) / 2;
9803 
9804 		if (classoid < middle->classoid)
9805 			high = middle - 1;
9806 		else if (classoid > middle->classoid)
9807 			low = middle + 1;
9808 		else if (objoid < middle->objoid)
9809 			high = middle - 1;
9810 		else if (objoid > middle->objoid)
9811 			low = middle + 1;
9812 		else
9813 			break;				/* found a match */
9814 	}
9815 
9816 	if (low > high)				/* no matches */
9817 	{
9818 		*items = NULL;
9819 		return 0;
9820 	}
9821 
9822 	/*
9823 	 * Now determine how many items match the object.  The search loop
9824 	 * invariant still holds: only items between low and high inclusive could
9825 	 * match.
9826 	 */
9827 	nmatch = 1;
9828 	while (middle > low)
9829 	{
9830 		if (classoid != middle[-1].classoid ||
9831 			objoid != middle[-1].objoid)
9832 			break;
9833 		middle--;
9834 		nmatch++;
9835 	}
9836 
9837 	*items = middle;
9838 
9839 	middle += nmatch;
9840 	while (middle <= high)
9841 	{
9842 		if (classoid != middle->classoid ||
9843 			objoid != middle->objoid)
9844 			break;
9845 		middle++;
9846 		nmatch++;
9847 	}
9848 
9849 	return nmatch;
9850 }
9851 
9852 /*
9853  * collectComments --
9854  *
9855  * Construct a table of all comments available for database objects.
9856  * We used to do per-object queries for the comments, but it's much faster
9857  * to pull them all over at once, and on most databases the memory cost
9858  * isn't high.
9859  *
9860  * The table is sorted by classoid/objid/objsubid for speed in lookup.
9861  */
9862 static int
collectComments(Archive * fout,CommentItem ** items)9863 collectComments(Archive *fout, CommentItem **items)
9864 {
9865 	PGresult   *res;
9866 	PQExpBuffer query;
9867 	int			i_description;
9868 	int			i_classoid;
9869 	int			i_objoid;
9870 	int			i_objsubid;
9871 	int			ntups;
9872 	int			i;
9873 	CommentItem *comments;
9874 
9875 	query = createPQExpBuffer();
9876 
9877 	appendPQExpBufferStr(query, "SELECT description, classoid, objoid, objsubid "
9878 						 "FROM pg_catalog.pg_description "
9879 						 "ORDER BY classoid, objoid, objsubid");
9880 
9881 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
9882 
9883 	/* Construct lookup table containing OIDs in numeric form */
9884 
9885 	i_description = PQfnumber(res, "description");
9886 	i_classoid = PQfnumber(res, "classoid");
9887 	i_objoid = PQfnumber(res, "objoid");
9888 	i_objsubid = PQfnumber(res, "objsubid");
9889 
9890 	ntups = PQntuples(res);
9891 
9892 	comments = (CommentItem *) pg_malloc(ntups * sizeof(CommentItem));
9893 
9894 	for (i = 0; i < ntups; i++)
9895 	{
9896 		comments[i].descr = PQgetvalue(res, i, i_description);
9897 		comments[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
9898 		comments[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
9899 		comments[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
9900 	}
9901 
9902 	/* Do NOT free the PGresult since we are keeping pointers into it */
9903 	destroyPQExpBuffer(query);
9904 
9905 	*items = comments;
9906 	return ntups;
9907 }
9908 
9909 /*
9910  * dumpDumpableObject
9911  *
9912  * This routine and its subsidiaries are responsible for creating
9913  * ArchiveEntries (TOC objects) for each object to be dumped.
9914  */
9915 static void
dumpDumpableObject(Archive * fout,DumpableObject * dobj)9916 dumpDumpableObject(Archive *fout, DumpableObject *dobj)
9917 {
9918 	switch (dobj->objType)
9919 	{
9920 		case DO_NAMESPACE:
9921 			dumpNamespace(fout, (NamespaceInfo *) dobj);
9922 			break;
9923 		case DO_EXTENSION:
9924 			dumpExtension(fout, (ExtensionInfo *) dobj);
9925 			break;
9926 		case DO_TYPE:
9927 			dumpType(fout, (TypeInfo *) dobj);
9928 			break;
9929 		case DO_SHELL_TYPE:
9930 			dumpShellType(fout, (ShellTypeInfo *) dobj);
9931 			break;
9932 		case DO_FUNC:
9933 			dumpFunc(fout, (FuncInfo *) dobj);
9934 			break;
9935 		case DO_AGG:
9936 			dumpAgg(fout, (AggInfo *) dobj);
9937 			break;
9938 		case DO_OPERATOR:
9939 			dumpOpr(fout, (OprInfo *) dobj);
9940 			break;
9941 		case DO_ACCESS_METHOD:
9942 			dumpAccessMethod(fout, (AccessMethodInfo *) dobj);
9943 			break;
9944 		case DO_OPCLASS:
9945 			dumpOpclass(fout, (OpclassInfo *) dobj);
9946 			break;
9947 		case DO_OPFAMILY:
9948 			dumpOpfamily(fout, (OpfamilyInfo *) dobj);
9949 			break;
9950 		case DO_COLLATION:
9951 			dumpCollation(fout, (CollInfo *) dobj);
9952 			break;
9953 		case DO_CONVERSION:
9954 			dumpConversion(fout, (ConvInfo *) dobj);
9955 			break;
9956 		case DO_TABLE:
9957 			dumpTable(fout, (TableInfo *) dobj);
9958 			break;
9959 		case DO_ATTRDEF:
9960 			dumpAttrDef(fout, (AttrDefInfo *) dobj);
9961 			break;
9962 		case DO_INDEX:
9963 			dumpIndex(fout, (IndxInfo *) dobj);
9964 			break;
9965 		case DO_INDEX_ATTACH:
9966 			dumpIndexAttach(fout, (IndexAttachInfo *) dobj);
9967 			break;
9968 		case DO_STATSEXT:
9969 			dumpStatisticsExt(fout, (StatsExtInfo *) dobj);
9970 			break;
9971 		case DO_REFRESH_MATVIEW:
9972 			refreshMatViewData(fout, (TableDataInfo *) dobj);
9973 			break;
9974 		case DO_RULE:
9975 			dumpRule(fout, (RuleInfo *) dobj);
9976 			break;
9977 		case DO_TRIGGER:
9978 			dumpTrigger(fout, (TriggerInfo *) dobj);
9979 			break;
9980 		case DO_EVENT_TRIGGER:
9981 			dumpEventTrigger(fout, (EventTriggerInfo *) dobj);
9982 			break;
9983 		case DO_CONSTRAINT:
9984 			dumpConstraint(fout, (ConstraintInfo *) dobj);
9985 			break;
9986 		case DO_FK_CONSTRAINT:
9987 			dumpConstraint(fout, (ConstraintInfo *) dobj);
9988 			break;
9989 		case DO_PROCLANG:
9990 			dumpProcLang(fout, (ProcLangInfo *) dobj);
9991 			break;
9992 		case DO_CAST:
9993 			dumpCast(fout, (CastInfo *) dobj);
9994 			break;
9995 		case DO_TRANSFORM:
9996 			dumpTransform(fout, (TransformInfo *) dobj);
9997 			break;
9998 		case DO_SEQUENCE_SET:
9999 			dumpSequenceData(fout, (TableDataInfo *) dobj);
10000 			break;
10001 		case DO_TABLE_DATA:
10002 			dumpTableData(fout, (TableDataInfo *) dobj);
10003 			break;
10004 		case DO_DUMMY_TYPE:
10005 			/* table rowtypes and array types are never dumped separately */
10006 			break;
10007 		case DO_TSPARSER:
10008 			dumpTSParser(fout, (TSParserInfo *) dobj);
10009 			break;
10010 		case DO_TSDICT:
10011 			dumpTSDictionary(fout, (TSDictInfo *) dobj);
10012 			break;
10013 		case DO_TSTEMPLATE:
10014 			dumpTSTemplate(fout, (TSTemplateInfo *) dobj);
10015 			break;
10016 		case DO_TSCONFIG:
10017 			dumpTSConfig(fout, (TSConfigInfo *) dobj);
10018 			break;
10019 		case DO_FDW:
10020 			dumpForeignDataWrapper(fout, (FdwInfo *) dobj);
10021 			break;
10022 		case DO_FOREIGN_SERVER:
10023 			dumpForeignServer(fout, (ForeignServerInfo *) dobj);
10024 			break;
10025 		case DO_DEFAULT_ACL:
10026 			dumpDefaultACL(fout, (DefaultACLInfo *) dobj);
10027 			break;
10028 		case DO_BLOB:
10029 			dumpBlob(fout, (BlobInfo *) dobj);
10030 			break;
10031 		case DO_BLOB_DATA:
10032 			if (dobj->dump & DUMP_COMPONENT_DATA)
10033 				ArchiveEntry(fout, dobj->catId, dobj->dumpId,
10034 							 dobj->name, NULL, NULL, "",
10035 							 false, "BLOBS", SECTION_DATA,
10036 							 "", "", NULL,
10037 							 NULL, 0,
10038 							 dumpBlobs, NULL);
10039 			break;
10040 		case DO_POLICY:
10041 			dumpPolicy(fout, (PolicyInfo *) dobj);
10042 			break;
10043 		case DO_PUBLICATION:
10044 			dumpPublication(fout, (PublicationInfo *) dobj);
10045 			break;
10046 		case DO_PUBLICATION_REL:
10047 			dumpPublicationTable(fout, (PublicationRelInfo *) dobj);
10048 			break;
10049 		case DO_SUBSCRIPTION:
10050 			dumpSubscription(fout, (SubscriptionInfo *) dobj);
10051 			break;
10052 		case DO_PRE_DATA_BOUNDARY:
10053 		case DO_POST_DATA_BOUNDARY:
10054 			/* never dumped, nothing to do */
10055 			break;
10056 	}
10057 }
10058 
10059 /*
10060  * dumpNamespace
10061  *	  writes out to fout the queries to recreate a user-defined namespace
10062  */
10063 static void
dumpNamespace(Archive * fout,NamespaceInfo * nspinfo)10064 dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
10065 {
10066 	DumpOptions *dopt = fout->dopt;
10067 	PQExpBuffer q;
10068 	PQExpBuffer delq;
10069 	char	   *qnspname;
10070 
10071 	/* Skip if not to be dumped */
10072 	if (!nspinfo->dobj.dump || dopt->dataOnly)
10073 		return;
10074 
10075 	q = createPQExpBuffer();
10076 	delq = createPQExpBuffer();
10077 
10078 	qnspname = pg_strdup(fmtId(nspinfo->dobj.name));
10079 
10080 	appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
10081 
10082 	appendPQExpBuffer(q, "CREATE SCHEMA %s;\n", qnspname);
10083 
10084 	if (dopt->binary_upgrade)
10085 		binary_upgrade_extension_member(q, &nspinfo->dobj,
10086 										"SCHEMA", qnspname, NULL);
10087 
10088 	if (nspinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10089 		ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
10090 					 nspinfo->dobj.name,
10091 					 NULL, NULL,
10092 					 nspinfo->rolname,
10093 					 false, "SCHEMA", SECTION_PRE_DATA,
10094 					 q->data, delq->data, NULL,
10095 					 NULL, 0,
10096 					 NULL, NULL);
10097 
10098 	/* Dump Schema Comments and Security Labels */
10099 	if (nspinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10100 		dumpComment(fout, "SCHEMA", qnspname,
10101 					NULL, nspinfo->rolname,
10102 					nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
10103 
10104 	if (nspinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10105 		dumpSecLabel(fout, "SCHEMA", qnspname,
10106 					 NULL, nspinfo->rolname,
10107 					 nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
10108 
10109 	if (nspinfo->dobj.dump & DUMP_COMPONENT_ACL)
10110 		dumpACL(fout, nspinfo->dobj.dumpId, InvalidDumpId, "SCHEMA",
10111 				qnspname, NULL, NULL,
10112 				nspinfo->rolname, nspinfo->nspacl, nspinfo->rnspacl,
10113 				nspinfo->initnspacl, nspinfo->initrnspacl);
10114 
10115 	free(qnspname);
10116 
10117 	destroyPQExpBuffer(q);
10118 	destroyPQExpBuffer(delq);
10119 }
10120 
10121 /*
10122  * dumpExtension
10123  *	  writes out to fout the queries to recreate an extension
10124  */
10125 static void
dumpExtension(Archive * fout,ExtensionInfo * extinfo)10126 dumpExtension(Archive *fout, ExtensionInfo *extinfo)
10127 {
10128 	DumpOptions *dopt = fout->dopt;
10129 	PQExpBuffer q;
10130 	PQExpBuffer delq;
10131 	char	   *qextname;
10132 
10133 	/* Skip if not to be dumped */
10134 	if (!extinfo->dobj.dump || dopt->dataOnly)
10135 		return;
10136 
10137 	q = createPQExpBuffer();
10138 	delq = createPQExpBuffer();
10139 
10140 	qextname = pg_strdup(fmtId(extinfo->dobj.name));
10141 
10142 	appendPQExpBuffer(delq, "DROP EXTENSION %s;\n", qextname);
10143 
10144 	if (!dopt->binary_upgrade)
10145 	{
10146 		/*
10147 		 * In a regular dump, we simply create the extension, intentionally
10148 		 * not specifying a version, so that the destination installation's
10149 		 * default version is used.
10150 		 *
10151 		 * Use of IF NOT EXISTS here is unlike our behavior for other object
10152 		 * types; but there are various scenarios in which it's convenient to
10153 		 * manually create the desired extension before restoring, so we
10154 		 * prefer to allow it to exist already.
10155 		 */
10156 		appendPQExpBuffer(q, "CREATE EXTENSION IF NOT EXISTS %s WITH SCHEMA %s;\n",
10157 						  qextname, fmtId(extinfo->namespace));
10158 	}
10159 	else
10160 	{
10161 		/*
10162 		 * In binary-upgrade mode, it's critical to reproduce the state of the
10163 		 * database exactly, so our procedure is to create an empty extension,
10164 		 * restore all the contained objects normally, and add them to the
10165 		 * extension one by one.  This function performs just the first of
10166 		 * those steps.  binary_upgrade_extension_member() takes care of
10167 		 * adding member objects as they're created.
10168 		 */
10169 		int			i;
10170 		int			n;
10171 
10172 		appendPQExpBufferStr(q, "-- For binary upgrade, create an empty extension and insert objects into it\n");
10173 
10174 		/*
10175 		 * We unconditionally create the extension, so we must drop it if it
10176 		 * exists.  This could happen if the user deleted 'plpgsql' and then
10177 		 * readded it, causing its oid to be greater than g_last_builtin_oid.
10178 		 */
10179 		appendPQExpBuffer(q, "DROP EXTENSION IF EXISTS %s;\n", qextname);
10180 
10181 		appendPQExpBufferStr(q,
10182 							 "SELECT pg_catalog.binary_upgrade_create_empty_extension(");
10183 		appendStringLiteralAH(q, extinfo->dobj.name, fout);
10184 		appendPQExpBufferStr(q, ", ");
10185 		appendStringLiteralAH(q, extinfo->namespace, fout);
10186 		appendPQExpBufferStr(q, ", ");
10187 		appendPQExpBuffer(q, "%s, ", extinfo->relocatable ? "true" : "false");
10188 		appendStringLiteralAH(q, extinfo->extversion, fout);
10189 		appendPQExpBufferStr(q, ", ");
10190 
10191 		/*
10192 		 * Note that we're pushing extconfig (an OID array) back into
10193 		 * pg_extension exactly as-is.  This is OK because pg_class OIDs are
10194 		 * preserved in binary upgrade.
10195 		 */
10196 		if (strlen(extinfo->extconfig) > 2)
10197 			appendStringLiteralAH(q, extinfo->extconfig, fout);
10198 		else
10199 			appendPQExpBufferStr(q, "NULL");
10200 		appendPQExpBufferStr(q, ", ");
10201 		if (strlen(extinfo->extcondition) > 2)
10202 			appendStringLiteralAH(q, extinfo->extcondition, fout);
10203 		else
10204 			appendPQExpBufferStr(q, "NULL");
10205 		appendPQExpBufferStr(q, ", ");
10206 		appendPQExpBufferStr(q, "ARRAY[");
10207 		n = 0;
10208 		for (i = 0; i < extinfo->dobj.nDeps; i++)
10209 		{
10210 			DumpableObject *extobj;
10211 
10212 			extobj = findObjectByDumpId(extinfo->dobj.dependencies[i]);
10213 			if (extobj && extobj->objType == DO_EXTENSION)
10214 			{
10215 				if (n++ > 0)
10216 					appendPQExpBufferChar(q, ',');
10217 				appendStringLiteralAH(q, extobj->name, fout);
10218 			}
10219 		}
10220 		appendPQExpBufferStr(q, "]::pg_catalog.text[]");
10221 		appendPQExpBufferStr(q, ");\n");
10222 	}
10223 
10224 	if (extinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10225 		ArchiveEntry(fout, extinfo->dobj.catId, extinfo->dobj.dumpId,
10226 					 extinfo->dobj.name,
10227 					 NULL, NULL,
10228 					 "",
10229 					 false, "EXTENSION", SECTION_PRE_DATA,
10230 					 q->data, delq->data, NULL,
10231 					 NULL, 0,
10232 					 NULL, NULL);
10233 
10234 	/* Dump Extension Comments and Security Labels */
10235 	if (extinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10236 		dumpComment(fout, "EXTENSION", qextname,
10237 					NULL, "",
10238 					extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
10239 
10240 	if (extinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10241 		dumpSecLabel(fout, "EXTENSION", qextname,
10242 					 NULL, "",
10243 					 extinfo->dobj.catId, 0, extinfo->dobj.dumpId);
10244 
10245 	free(qextname);
10246 
10247 	destroyPQExpBuffer(q);
10248 	destroyPQExpBuffer(delq);
10249 }
10250 
10251 /*
10252  * dumpType
10253  *	  writes out to fout the queries to recreate a user-defined type
10254  */
10255 static void
dumpType(Archive * fout,TypeInfo * tyinfo)10256 dumpType(Archive *fout, TypeInfo *tyinfo)
10257 {
10258 	DumpOptions *dopt = fout->dopt;
10259 
10260 	/* Skip if not to be dumped */
10261 	if (!tyinfo->dobj.dump || dopt->dataOnly)
10262 		return;
10263 
10264 	/* Dump out in proper style */
10265 	if (tyinfo->typtype == TYPTYPE_BASE)
10266 		dumpBaseType(fout, tyinfo);
10267 	else if (tyinfo->typtype == TYPTYPE_DOMAIN)
10268 		dumpDomain(fout, tyinfo);
10269 	else if (tyinfo->typtype == TYPTYPE_COMPOSITE)
10270 		dumpCompositeType(fout, tyinfo);
10271 	else if (tyinfo->typtype == TYPTYPE_ENUM)
10272 		dumpEnumType(fout, tyinfo);
10273 	else if (tyinfo->typtype == TYPTYPE_RANGE)
10274 		dumpRangeType(fout, tyinfo);
10275 	else if (tyinfo->typtype == TYPTYPE_PSEUDO && !tyinfo->isDefined)
10276 		dumpUndefinedType(fout, tyinfo);
10277 	else
10278 		write_msg(NULL, "WARNING: typtype of data type \"%s\" appears to be invalid\n",
10279 				  tyinfo->dobj.name);
10280 }
10281 
10282 /*
10283  * dumpEnumType
10284  *	  writes out to fout the queries to recreate a user-defined enum type
10285  */
10286 static void
dumpEnumType(Archive * fout,TypeInfo * tyinfo)10287 dumpEnumType(Archive *fout, TypeInfo *tyinfo)
10288 {
10289 	DumpOptions *dopt = fout->dopt;
10290 	PQExpBuffer q = createPQExpBuffer();
10291 	PQExpBuffer delq = createPQExpBuffer();
10292 	PQExpBuffer query = createPQExpBuffer();
10293 	PGresult   *res;
10294 	int			num,
10295 				i;
10296 	Oid			enum_oid;
10297 	char	   *qtypname;
10298 	char	   *qualtypname;
10299 	char	   *label;
10300 
10301 	if (fout->remoteVersion >= 90100)
10302 		appendPQExpBuffer(query, "SELECT oid, enumlabel "
10303 						  "FROM pg_catalog.pg_enum "
10304 						  "WHERE enumtypid = '%u'"
10305 						  "ORDER BY enumsortorder",
10306 						  tyinfo->dobj.catId.oid);
10307 	else
10308 		appendPQExpBuffer(query, "SELECT oid, enumlabel "
10309 						  "FROM pg_catalog.pg_enum "
10310 						  "WHERE enumtypid = '%u'"
10311 						  "ORDER BY oid",
10312 						  tyinfo->dobj.catId.oid);
10313 
10314 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
10315 
10316 	num = PQntuples(res);
10317 
10318 	qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10319 	qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10320 
10321 	/*
10322 	 * CASCADE shouldn't be required here as for normal types since the I/O
10323 	 * functions are generic and do not get dropped.
10324 	 */
10325 	appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
10326 
10327 	if (dopt->binary_upgrade)
10328 		binary_upgrade_set_type_oids_by_type_oid(fout, q,
10329 												 tyinfo->dobj.catId.oid,
10330 												 false);
10331 
10332 	appendPQExpBuffer(q, "CREATE TYPE %s AS ENUM (",
10333 					  qualtypname);
10334 
10335 	if (!dopt->binary_upgrade)
10336 	{
10337 		/* Labels with server-assigned oids */
10338 		for (i = 0; i < num; i++)
10339 		{
10340 			label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
10341 			if (i > 0)
10342 				appendPQExpBufferChar(q, ',');
10343 			appendPQExpBufferStr(q, "\n    ");
10344 			appendStringLiteralAH(q, label, fout);
10345 		}
10346 	}
10347 
10348 	appendPQExpBufferStr(q, "\n);\n");
10349 
10350 	if (dopt->binary_upgrade)
10351 	{
10352 		/* Labels with dump-assigned (preserved) oids */
10353 		for (i = 0; i < num; i++)
10354 		{
10355 			enum_oid = atooid(PQgetvalue(res, i, PQfnumber(res, "oid")));
10356 			label = PQgetvalue(res, i, PQfnumber(res, "enumlabel"));
10357 
10358 			if (i == 0)
10359 				appendPQExpBufferStr(q, "\n-- For binary upgrade, must preserve pg_enum oids\n");
10360 			appendPQExpBuffer(q,
10361 							  "SELECT pg_catalog.binary_upgrade_set_next_pg_enum_oid('%u'::pg_catalog.oid);\n",
10362 							  enum_oid);
10363 			appendPQExpBuffer(q, "ALTER TYPE %s ADD VALUE ", qualtypname);
10364 			appendStringLiteralAH(q, label, fout);
10365 			appendPQExpBufferStr(q, ";\n\n");
10366 		}
10367 	}
10368 
10369 	if (dopt->binary_upgrade)
10370 		binary_upgrade_extension_member(q, &tyinfo->dobj,
10371 										"TYPE", qtypname,
10372 										tyinfo->dobj.namespace->dobj.name);
10373 
10374 	if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10375 		ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10376 					 tyinfo->dobj.name,
10377 					 tyinfo->dobj.namespace->dobj.name,
10378 					 NULL,
10379 					 tyinfo->rolname, false,
10380 					 "TYPE", SECTION_PRE_DATA,
10381 					 q->data, delq->data, NULL,
10382 					 NULL, 0,
10383 					 NULL, NULL);
10384 
10385 	/* Dump Type Comments and Security Labels */
10386 	if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10387 		dumpComment(fout, "TYPE", qtypname,
10388 					tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10389 					tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10390 
10391 	if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10392 		dumpSecLabel(fout, "TYPE", qtypname,
10393 					 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10394 					 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10395 
10396 	if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10397 		dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
10398 				qtypname, NULL,
10399 				tyinfo->dobj.namespace->dobj.name,
10400 				tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10401 				tyinfo->inittypacl, tyinfo->initrtypacl);
10402 
10403 	PQclear(res);
10404 	destroyPQExpBuffer(q);
10405 	destroyPQExpBuffer(delq);
10406 	destroyPQExpBuffer(query);
10407 	free(qtypname);
10408 	free(qualtypname);
10409 }
10410 
10411 /*
10412  * dumpRangeType
10413  *	  writes out to fout the queries to recreate a user-defined range type
10414  */
10415 static void
dumpRangeType(Archive * fout,TypeInfo * tyinfo)10416 dumpRangeType(Archive *fout, TypeInfo *tyinfo)
10417 {
10418 	DumpOptions *dopt = fout->dopt;
10419 	PQExpBuffer q = createPQExpBuffer();
10420 	PQExpBuffer delq = createPQExpBuffer();
10421 	PQExpBuffer query = createPQExpBuffer();
10422 	PGresult   *res;
10423 	Oid			collationOid;
10424 	char	   *qtypname;
10425 	char	   *qualtypname;
10426 	char	   *procname;
10427 
10428 	appendPQExpBuffer(query,
10429 					  "SELECT pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
10430 					  "opc.opcname AS opcname, "
10431 					  "(SELECT nspname FROM pg_catalog.pg_namespace nsp "
10432 					  "  WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
10433 					  "opc.opcdefault, "
10434 					  "CASE WHEN rngcollation = st.typcollation THEN 0 "
10435 					  "     ELSE rngcollation END AS collation, "
10436 					  "rngcanonical, rngsubdiff "
10437 					  "FROM pg_catalog.pg_range r, pg_catalog.pg_type st, "
10438 					  "     pg_catalog.pg_opclass opc "
10439 					  "WHERE st.oid = rngsubtype AND opc.oid = rngsubopc AND "
10440 					  "rngtypid = '%u'",
10441 					  tyinfo->dobj.catId.oid);
10442 
10443 	res = ExecuteSqlQueryForSingleRow(fout, query->data);
10444 
10445 	qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10446 	qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10447 
10448 	/*
10449 	 * CASCADE shouldn't be required here as for normal types since the I/O
10450 	 * functions are generic and do not get dropped.
10451 	 */
10452 	appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
10453 
10454 	if (dopt->binary_upgrade)
10455 		binary_upgrade_set_type_oids_by_type_oid(fout, q,
10456 												 tyinfo->dobj.catId.oid,
10457 												 false);
10458 
10459 	appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
10460 					  qualtypname);
10461 
10462 	appendPQExpBuffer(q, "\n    subtype = %s",
10463 					  PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
10464 
10465 	/* print subtype_opclass only if not default for subtype */
10466 	if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
10467 	{
10468 		char	   *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
10469 		char	   *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
10470 
10471 		appendPQExpBuffer(q, ",\n    subtype_opclass = %s.",
10472 						  fmtId(nspname));
10473 		appendPQExpBufferStr(q, fmtId(opcname));
10474 	}
10475 
10476 	collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
10477 	if (OidIsValid(collationOid))
10478 	{
10479 		CollInfo   *coll = findCollationByOid(collationOid);
10480 
10481 		if (coll)
10482 			appendPQExpBuffer(q, ",\n    collation = %s",
10483 							  fmtQualifiedDumpable(coll));
10484 	}
10485 
10486 	procname = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
10487 	if (strcmp(procname, "-") != 0)
10488 		appendPQExpBuffer(q, ",\n    canonical = %s", procname);
10489 
10490 	procname = PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff"));
10491 	if (strcmp(procname, "-") != 0)
10492 		appendPQExpBuffer(q, ",\n    subtype_diff = %s", procname);
10493 
10494 	appendPQExpBufferStr(q, "\n);\n");
10495 
10496 	if (dopt->binary_upgrade)
10497 		binary_upgrade_extension_member(q, &tyinfo->dobj,
10498 										"TYPE", qtypname,
10499 										tyinfo->dobj.namespace->dobj.name);
10500 
10501 	if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10502 		ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10503 					 tyinfo->dobj.name,
10504 					 tyinfo->dobj.namespace->dobj.name,
10505 					 NULL,
10506 					 tyinfo->rolname, false,
10507 					 "TYPE", SECTION_PRE_DATA,
10508 					 q->data, delq->data, NULL,
10509 					 NULL, 0,
10510 					 NULL, NULL);
10511 
10512 	/* Dump Type Comments and Security Labels */
10513 	if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10514 		dumpComment(fout, "TYPE", qtypname,
10515 					tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10516 					tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10517 
10518 	if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10519 		dumpSecLabel(fout, "TYPE", qtypname,
10520 					 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10521 					 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10522 
10523 	if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10524 		dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
10525 				qtypname, NULL,
10526 				tyinfo->dobj.namespace->dobj.name,
10527 				tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10528 				tyinfo->inittypacl, tyinfo->initrtypacl);
10529 
10530 	PQclear(res);
10531 	destroyPQExpBuffer(q);
10532 	destroyPQExpBuffer(delq);
10533 	destroyPQExpBuffer(query);
10534 	free(qtypname);
10535 	free(qualtypname);
10536 }
10537 
10538 /*
10539  * dumpUndefinedType
10540  *	  writes out to fout the queries to recreate a !typisdefined type
10541  *
10542  * This is a shell type, but we use different terminology to distinguish
10543  * this case from where we have to emit a shell type definition to break
10544  * circular dependencies.  An undefined type shouldn't ever have anything
10545  * depending on it.
10546  */
10547 static void
dumpUndefinedType(Archive * fout,TypeInfo * tyinfo)10548 dumpUndefinedType(Archive *fout, TypeInfo *tyinfo)
10549 {
10550 	DumpOptions *dopt = fout->dopt;
10551 	PQExpBuffer q = createPQExpBuffer();
10552 	PQExpBuffer delq = createPQExpBuffer();
10553 	char	   *qtypname;
10554 	char	   *qualtypname;
10555 
10556 	qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10557 	qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10558 
10559 	appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
10560 
10561 	if (dopt->binary_upgrade)
10562 		binary_upgrade_set_type_oids_by_type_oid(fout, q,
10563 												 tyinfo->dobj.catId.oid,
10564 												 false);
10565 
10566 	appendPQExpBuffer(q, "CREATE TYPE %s;\n",
10567 					  qualtypname);
10568 
10569 	if (dopt->binary_upgrade)
10570 		binary_upgrade_extension_member(q, &tyinfo->dobj,
10571 										"TYPE", qtypname,
10572 										tyinfo->dobj.namespace->dobj.name);
10573 
10574 	if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10575 		ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10576 					 tyinfo->dobj.name,
10577 					 tyinfo->dobj.namespace->dobj.name,
10578 					 NULL,
10579 					 tyinfo->rolname, false,
10580 					 "TYPE", SECTION_PRE_DATA,
10581 					 q->data, delq->data, NULL,
10582 					 NULL, 0,
10583 					 NULL, NULL);
10584 
10585 	/* Dump Type Comments and Security Labels */
10586 	if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10587 		dumpComment(fout, "TYPE", qtypname,
10588 					tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10589 					tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10590 
10591 	if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10592 		dumpSecLabel(fout, "TYPE", qtypname,
10593 					 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10594 					 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10595 
10596 	if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10597 		dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
10598 				qtypname, NULL,
10599 				tyinfo->dobj.namespace->dobj.name,
10600 				tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10601 				tyinfo->inittypacl, tyinfo->initrtypacl);
10602 
10603 	destroyPQExpBuffer(q);
10604 	destroyPQExpBuffer(delq);
10605 	free(qtypname);
10606 	free(qualtypname);
10607 }
10608 
10609 /*
10610  * dumpBaseType
10611  *	  writes out to fout the queries to recreate a user-defined base type
10612  */
10613 static void
dumpBaseType(Archive * fout,TypeInfo * tyinfo)10614 dumpBaseType(Archive *fout, TypeInfo *tyinfo)
10615 {
10616 	DumpOptions *dopt = fout->dopt;
10617 	PQExpBuffer q = createPQExpBuffer();
10618 	PQExpBuffer delq = createPQExpBuffer();
10619 	PQExpBuffer query = createPQExpBuffer();
10620 	PGresult   *res;
10621 	char	   *qtypname;
10622 	char	   *qualtypname;
10623 	char	   *typlen;
10624 	char	   *typinput;
10625 	char	   *typoutput;
10626 	char	   *typreceive;
10627 	char	   *typsend;
10628 	char	   *typmodin;
10629 	char	   *typmodout;
10630 	char	   *typanalyze;
10631 	Oid			typreceiveoid;
10632 	Oid			typsendoid;
10633 	Oid			typmodinoid;
10634 	Oid			typmodoutoid;
10635 	Oid			typanalyzeoid;
10636 	char	   *typcategory;
10637 	char	   *typispreferred;
10638 	char	   *typdelim;
10639 	char	   *typbyval;
10640 	char	   *typalign;
10641 	char	   *typstorage;
10642 	char	   *typcollatable;
10643 	char	   *typdefault;
10644 	bool		typdefault_is_literal = false;
10645 
10646 	/* Fetch type-specific details */
10647 	if (fout->remoteVersion >= 90100)
10648 	{
10649 		appendPQExpBuffer(query, "SELECT typlen, "
10650 						  "typinput, typoutput, typreceive, typsend, "
10651 						  "typmodin, typmodout, typanalyze, "
10652 						  "typreceive::pg_catalog.oid AS typreceiveoid, "
10653 						  "typsend::pg_catalog.oid AS typsendoid, "
10654 						  "typmodin::pg_catalog.oid AS typmodinoid, "
10655 						  "typmodout::pg_catalog.oid AS typmodoutoid, "
10656 						  "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10657 						  "typcategory, typispreferred, "
10658 						  "typdelim, typbyval, typalign, typstorage, "
10659 						  "(typcollation <> 0) AS typcollatable, "
10660 						  "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
10661 						  "FROM pg_catalog.pg_type "
10662 						  "WHERE oid = '%u'::pg_catalog.oid",
10663 						  tyinfo->dobj.catId.oid);
10664 	}
10665 	else if (fout->remoteVersion >= 80400)
10666 	{
10667 		appendPQExpBuffer(query, "SELECT typlen, "
10668 						  "typinput, typoutput, typreceive, typsend, "
10669 						  "typmodin, typmodout, typanalyze, "
10670 						  "typreceive::pg_catalog.oid AS typreceiveoid, "
10671 						  "typsend::pg_catalog.oid AS typsendoid, "
10672 						  "typmodin::pg_catalog.oid AS typmodinoid, "
10673 						  "typmodout::pg_catalog.oid AS typmodoutoid, "
10674 						  "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10675 						  "typcategory, typispreferred, "
10676 						  "typdelim, typbyval, typalign, typstorage, "
10677 						  "false AS typcollatable, "
10678 						  "pg_catalog.pg_get_expr(typdefaultbin, 0) AS typdefaultbin, typdefault "
10679 						  "FROM pg_catalog.pg_type "
10680 						  "WHERE oid = '%u'::pg_catalog.oid",
10681 						  tyinfo->dobj.catId.oid);
10682 	}
10683 	else if (fout->remoteVersion >= 80300)
10684 	{
10685 		/* Before 8.4, pg_get_expr does not allow 0 for its second arg */
10686 		appendPQExpBuffer(query, "SELECT typlen, "
10687 						  "typinput, typoutput, typreceive, typsend, "
10688 						  "typmodin, typmodout, typanalyze, "
10689 						  "typreceive::pg_catalog.oid AS typreceiveoid, "
10690 						  "typsend::pg_catalog.oid AS typsendoid, "
10691 						  "typmodin::pg_catalog.oid AS typmodinoid, "
10692 						  "typmodout::pg_catalog.oid AS typmodoutoid, "
10693 						  "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10694 						  "'U' AS typcategory, false AS typispreferred, "
10695 						  "typdelim, typbyval, typalign, typstorage, "
10696 						  "false AS typcollatable, "
10697 						  "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
10698 						  "FROM pg_catalog.pg_type "
10699 						  "WHERE oid = '%u'::pg_catalog.oid",
10700 						  tyinfo->dobj.catId.oid);
10701 	}
10702 	else
10703 	{
10704 		appendPQExpBuffer(query, "SELECT typlen, "
10705 						  "typinput, typoutput, typreceive, typsend, "
10706 						  "'-' AS typmodin, '-' AS typmodout, "
10707 						  "typanalyze, "
10708 						  "typreceive::pg_catalog.oid AS typreceiveoid, "
10709 						  "typsend::pg_catalog.oid AS typsendoid, "
10710 						  "0 AS typmodinoid, 0 AS typmodoutoid, "
10711 						  "typanalyze::pg_catalog.oid AS typanalyzeoid, "
10712 						  "'U' AS typcategory, false AS typispreferred, "
10713 						  "typdelim, typbyval, typalign, typstorage, "
10714 						  "false AS typcollatable, "
10715 						  "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, typdefault "
10716 						  "FROM pg_catalog.pg_type "
10717 						  "WHERE oid = '%u'::pg_catalog.oid",
10718 						  tyinfo->dobj.catId.oid);
10719 	}
10720 
10721 	res = ExecuteSqlQueryForSingleRow(fout, query->data);
10722 
10723 	typlen = PQgetvalue(res, 0, PQfnumber(res, "typlen"));
10724 	typinput = PQgetvalue(res, 0, PQfnumber(res, "typinput"));
10725 	typoutput = PQgetvalue(res, 0, PQfnumber(res, "typoutput"));
10726 	typreceive = PQgetvalue(res, 0, PQfnumber(res, "typreceive"));
10727 	typsend = PQgetvalue(res, 0, PQfnumber(res, "typsend"));
10728 	typmodin = PQgetvalue(res, 0, PQfnumber(res, "typmodin"));
10729 	typmodout = PQgetvalue(res, 0, PQfnumber(res, "typmodout"));
10730 	typanalyze = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
10731 	typreceiveoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typreceiveoid")));
10732 	typsendoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typsendoid")));
10733 	typmodinoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodinoid")));
10734 	typmodoutoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typmodoutoid")));
10735 	typanalyzeoid = atooid(PQgetvalue(res, 0, PQfnumber(res, "typanalyzeoid")));
10736 	typcategory = PQgetvalue(res, 0, PQfnumber(res, "typcategory"));
10737 	typispreferred = PQgetvalue(res, 0, PQfnumber(res, "typispreferred"));
10738 	typdelim = PQgetvalue(res, 0, PQfnumber(res, "typdelim"));
10739 	typbyval = PQgetvalue(res, 0, PQfnumber(res, "typbyval"));
10740 	typalign = PQgetvalue(res, 0, PQfnumber(res, "typalign"));
10741 	typstorage = PQgetvalue(res, 0, PQfnumber(res, "typstorage"));
10742 	typcollatable = PQgetvalue(res, 0, PQfnumber(res, "typcollatable"));
10743 	if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
10744 		typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
10745 	else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
10746 	{
10747 		typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
10748 		typdefault_is_literal = true;	/* it needs quotes */
10749 	}
10750 	else
10751 		typdefault = NULL;
10752 
10753 	qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10754 	qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10755 
10756 	/*
10757 	 * The reason we include CASCADE is that the circular dependency between
10758 	 * the type and its I/O functions makes it impossible to drop the type any
10759 	 * other way.
10760 	 */
10761 	appendPQExpBuffer(delq, "DROP TYPE %s CASCADE;\n", qualtypname);
10762 
10763 	/*
10764 	 * We might already have a shell type, but setting pg_type_oid is
10765 	 * harmless, and in any case we'd better set the array type OID.
10766 	 */
10767 	if (dopt->binary_upgrade)
10768 		binary_upgrade_set_type_oids_by_type_oid(fout, q,
10769 												 tyinfo->dobj.catId.oid,
10770 												 false);
10771 
10772 	appendPQExpBuffer(q,
10773 					  "CREATE TYPE %s (\n"
10774 					  "    INTERNALLENGTH = %s",
10775 					  qualtypname,
10776 					  (strcmp(typlen, "-1") == 0) ? "variable" : typlen);
10777 
10778 	/* regproc result is sufficiently quoted already */
10779 	appendPQExpBuffer(q, ",\n    INPUT = %s", typinput);
10780 	appendPQExpBuffer(q, ",\n    OUTPUT = %s", typoutput);
10781 	if (OidIsValid(typreceiveoid))
10782 		appendPQExpBuffer(q, ",\n    RECEIVE = %s", typreceive);
10783 	if (OidIsValid(typsendoid))
10784 		appendPQExpBuffer(q, ",\n    SEND = %s", typsend);
10785 	if (OidIsValid(typmodinoid))
10786 		appendPQExpBuffer(q, ",\n    TYPMOD_IN = %s", typmodin);
10787 	if (OidIsValid(typmodoutoid))
10788 		appendPQExpBuffer(q, ",\n    TYPMOD_OUT = %s", typmodout);
10789 	if (OidIsValid(typanalyzeoid))
10790 		appendPQExpBuffer(q, ",\n    ANALYZE = %s", typanalyze);
10791 
10792 	if (strcmp(typcollatable, "t") == 0)
10793 		appendPQExpBufferStr(q, ",\n    COLLATABLE = true");
10794 
10795 	if (typdefault != NULL)
10796 	{
10797 		appendPQExpBufferStr(q, ",\n    DEFAULT = ");
10798 		if (typdefault_is_literal)
10799 			appendStringLiteralAH(q, typdefault, fout);
10800 		else
10801 			appendPQExpBufferStr(q, typdefault);
10802 	}
10803 
10804 	if (OidIsValid(tyinfo->typelem))
10805 		appendPQExpBuffer(q, ",\n    ELEMENT = %s",
10806 						  getFormattedTypeName(fout, tyinfo->typelem,
10807 											   zeroAsOpaque));
10808 
10809 	if (strcmp(typcategory, "U") != 0)
10810 	{
10811 		appendPQExpBufferStr(q, ",\n    CATEGORY = ");
10812 		appendStringLiteralAH(q, typcategory, fout);
10813 	}
10814 
10815 	if (strcmp(typispreferred, "t") == 0)
10816 		appendPQExpBufferStr(q, ",\n    PREFERRED = true");
10817 
10818 	if (typdelim && strcmp(typdelim, ",") != 0)
10819 	{
10820 		appendPQExpBufferStr(q, ",\n    DELIMITER = ");
10821 		appendStringLiteralAH(q, typdelim, fout);
10822 	}
10823 
10824 	if (strcmp(typalign, "c") == 0)
10825 		appendPQExpBufferStr(q, ",\n    ALIGNMENT = char");
10826 	else if (strcmp(typalign, "s") == 0)
10827 		appendPQExpBufferStr(q, ",\n    ALIGNMENT = int2");
10828 	else if (strcmp(typalign, "i") == 0)
10829 		appendPQExpBufferStr(q, ",\n    ALIGNMENT = int4");
10830 	else if (strcmp(typalign, "d") == 0)
10831 		appendPQExpBufferStr(q, ",\n    ALIGNMENT = double");
10832 
10833 	if (strcmp(typstorage, "p") == 0)
10834 		appendPQExpBufferStr(q, ",\n    STORAGE = plain");
10835 	else if (strcmp(typstorage, "e") == 0)
10836 		appendPQExpBufferStr(q, ",\n    STORAGE = external");
10837 	else if (strcmp(typstorage, "x") == 0)
10838 		appendPQExpBufferStr(q, ",\n    STORAGE = extended");
10839 	else if (strcmp(typstorage, "m") == 0)
10840 		appendPQExpBufferStr(q, ",\n    STORAGE = main");
10841 
10842 	if (strcmp(typbyval, "t") == 0)
10843 		appendPQExpBufferStr(q, ",\n    PASSEDBYVALUE");
10844 
10845 	appendPQExpBufferStr(q, "\n);\n");
10846 
10847 	if (dopt->binary_upgrade)
10848 		binary_upgrade_extension_member(q, &tyinfo->dobj,
10849 										"TYPE", qtypname,
10850 										tyinfo->dobj.namespace->dobj.name);
10851 
10852 	if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
10853 		ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
10854 					 tyinfo->dobj.name,
10855 					 tyinfo->dobj.namespace->dobj.name,
10856 					 NULL,
10857 					 tyinfo->rolname, false,
10858 					 "TYPE", SECTION_PRE_DATA,
10859 					 q->data, delq->data, NULL,
10860 					 NULL, 0,
10861 					 NULL, NULL);
10862 
10863 	/* Dump Type Comments and Security Labels */
10864 	if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
10865 		dumpComment(fout, "TYPE", qtypname,
10866 					tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10867 					tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10868 
10869 	if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
10870 		dumpSecLabel(fout, "TYPE", qtypname,
10871 					 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
10872 					 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
10873 
10874 	if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
10875 		dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
10876 				qtypname, NULL,
10877 				tyinfo->dobj.namespace->dobj.name,
10878 				tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
10879 				tyinfo->inittypacl, tyinfo->initrtypacl);
10880 
10881 	PQclear(res);
10882 	destroyPQExpBuffer(q);
10883 	destroyPQExpBuffer(delq);
10884 	destroyPQExpBuffer(query);
10885 	free(qtypname);
10886 	free(qualtypname);
10887 }
10888 
10889 /*
10890  * dumpDomain
10891  *	  writes out to fout the queries to recreate a user-defined domain
10892  */
10893 static void
dumpDomain(Archive * fout,TypeInfo * tyinfo)10894 dumpDomain(Archive *fout, TypeInfo *tyinfo)
10895 {
10896 	DumpOptions *dopt = fout->dopt;
10897 	PQExpBuffer q = createPQExpBuffer();
10898 	PQExpBuffer delq = createPQExpBuffer();
10899 	PQExpBuffer query = createPQExpBuffer();
10900 	PGresult   *res;
10901 	int			i;
10902 	char	   *qtypname;
10903 	char	   *qualtypname;
10904 	char	   *typnotnull;
10905 	char	   *typdefn;
10906 	char	   *typdefault;
10907 	Oid			typcollation;
10908 	bool		typdefault_is_literal = false;
10909 
10910 	/* Fetch domain specific details */
10911 	if (fout->remoteVersion >= 90100)
10912 	{
10913 		/* typcollation is new in 9.1 */
10914 		appendPQExpBuffer(query, "SELECT t.typnotnull, "
10915 						  "pg_catalog.format_type(t.typbasetype, t.typtypmod) AS typdefn, "
10916 						  "pg_catalog.pg_get_expr(t.typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
10917 						  "t.typdefault, "
10918 						  "CASE WHEN t.typcollation <> u.typcollation "
10919 						  "THEN t.typcollation ELSE 0 END AS typcollation "
10920 						  "FROM pg_catalog.pg_type t "
10921 						  "LEFT JOIN pg_catalog.pg_type u ON (t.typbasetype = u.oid) "
10922 						  "WHERE t.oid = '%u'::pg_catalog.oid",
10923 						  tyinfo->dobj.catId.oid);
10924 	}
10925 	else
10926 	{
10927 		appendPQExpBuffer(query, "SELECT typnotnull, "
10928 						  "pg_catalog.format_type(typbasetype, typtypmod) AS typdefn, "
10929 						  "pg_catalog.pg_get_expr(typdefaultbin, 'pg_catalog.pg_type'::pg_catalog.regclass) AS typdefaultbin, "
10930 						  "typdefault, 0 AS typcollation "
10931 						  "FROM pg_catalog.pg_type "
10932 						  "WHERE oid = '%u'::pg_catalog.oid",
10933 						  tyinfo->dobj.catId.oid);
10934 	}
10935 
10936 	res = ExecuteSqlQueryForSingleRow(fout, query->data);
10937 
10938 	typnotnull = PQgetvalue(res, 0, PQfnumber(res, "typnotnull"));
10939 	typdefn = PQgetvalue(res, 0, PQfnumber(res, "typdefn"));
10940 	if (!PQgetisnull(res, 0, PQfnumber(res, "typdefaultbin")))
10941 		typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefaultbin"));
10942 	else if (!PQgetisnull(res, 0, PQfnumber(res, "typdefault")))
10943 	{
10944 		typdefault = PQgetvalue(res, 0, PQfnumber(res, "typdefault"));
10945 		typdefault_is_literal = true;	/* it needs quotes */
10946 	}
10947 	else
10948 		typdefault = NULL;
10949 	typcollation = atooid(PQgetvalue(res, 0, PQfnumber(res, "typcollation")));
10950 
10951 	if (dopt->binary_upgrade)
10952 		binary_upgrade_set_type_oids_by_type_oid(fout, q,
10953 												 tyinfo->dobj.catId.oid,
10954 												 true); /* force array type */
10955 
10956 	qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
10957 	qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
10958 
10959 	appendPQExpBuffer(q,
10960 					  "CREATE DOMAIN %s AS %s",
10961 					  qualtypname,
10962 					  typdefn);
10963 
10964 	/* Print collation only if different from base type's collation */
10965 	if (OidIsValid(typcollation))
10966 	{
10967 		CollInfo   *coll;
10968 
10969 		coll = findCollationByOid(typcollation);
10970 		if (coll)
10971 			appendPQExpBuffer(q, " COLLATE %s", fmtQualifiedDumpable(coll));
10972 	}
10973 
10974 	if (typnotnull[0] == 't')
10975 		appendPQExpBufferStr(q, " NOT NULL");
10976 
10977 	if (typdefault != NULL)
10978 	{
10979 		appendPQExpBufferStr(q, " DEFAULT ");
10980 		if (typdefault_is_literal)
10981 			appendStringLiteralAH(q, typdefault, fout);
10982 		else
10983 			appendPQExpBufferStr(q, typdefault);
10984 	}
10985 
10986 	PQclear(res);
10987 
10988 	/*
10989 	 * Add any CHECK constraints for the domain
10990 	 */
10991 	for (i = 0; i < tyinfo->nDomChecks; i++)
10992 	{
10993 		ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
10994 
10995 		if (!domcheck->separate)
10996 			appendPQExpBuffer(q, "\n\tCONSTRAINT %s %s",
10997 							  fmtId(domcheck->dobj.name), domcheck->condef);
10998 	}
10999 
11000 	appendPQExpBufferStr(q, ";\n");
11001 
11002 	appendPQExpBuffer(delq, "DROP DOMAIN %s;\n", qualtypname);
11003 
11004 	if (dopt->binary_upgrade)
11005 		binary_upgrade_extension_member(q, &tyinfo->dobj,
11006 										"DOMAIN", qtypname,
11007 										tyinfo->dobj.namespace->dobj.name);
11008 
11009 	if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11010 		ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
11011 					 tyinfo->dobj.name,
11012 					 tyinfo->dobj.namespace->dobj.name,
11013 					 NULL,
11014 					 tyinfo->rolname, false,
11015 					 "DOMAIN", SECTION_PRE_DATA,
11016 					 q->data, delq->data, NULL,
11017 					 NULL, 0,
11018 					 NULL, NULL);
11019 
11020 	/* Dump Domain Comments and Security Labels */
11021 	if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
11022 		dumpComment(fout, "DOMAIN", qtypname,
11023 					tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11024 					tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11025 
11026 	if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
11027 		dumpSecLabel(fout, "DOMAIN", qtypname,
11028 					 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11029 					 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11030 
11031 	if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
11032 		dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
11033 				qtypname, NULL,
11034 				tyinfo->dobj.namespace->dobj.name,
11035 				tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
11036 				tyinfo->inittypacl, tyinfo->initrtypacl);
11037 
11038 	/* Dump any per-constraint comments */
11039 	for (i = 0; i < tyinfo->nDomChecks; i++)
11040 	{
11041 		ConstraintInfo *domcheck = &(tyinfo->domChecks[i]);
11042 		PQExpBuffer conprefix = createPQExpBuffer();
11043 
11044 		appendPQExpBuffer(conprefix, "CONSTRAINT %s ON DOMAIN",
11045 						  fmtId(domcheck->dobj.name));
11046 
11047 		if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
11048 			dumpComment(fout, conprefix->data, qtypname,
11049 						tyinfo->dobj.namespace->dobj.name,
11050 						tyinfo->rolname,
11051 						domcheck->dobj.catId, 0, tyinfo->dobj.dumpId);
11052 
11053 		destroyPQExpBuffer(conprefix);
11054 	}
11055 
11056 	destroyPQExpBuffer(q);
11057 	destroyPQExpBuffer(delq);
11058 	destroyPQExpBuffer(query);
11059 	free(qtypname);
11060 	free(qualtypname);
11061 }
11062 
11063 /*
11064  * dumpCompositeType
11065  *	  writes out to fout the queries to recreate a user-defined stand-alone
11066  *	  composite type
11067  */
11068 static void
dumpCompositeType(Archive * fout,TypeInfo * tyinfo)11069 dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
11070 {
11071 	DumpOptions *dopt = fout->dopt;
11072 	PQExpBuffer q = createPQExpBuffer();
11073 	PQExpBuffer dropped = createPQExpBuffer();
11074 	PQExpBuffer delq = createPQExpBuffer();
11075 	PQExpBuffer query = createPQExpBuffer();
11076 	PGresult   *res;
11077 	char	   *qtypname;
11078 	char	   *qualtypname;
11079 	int			ntups;
11080 	int			i_attname;
11081 	int			i_atttypdefn;
11082 	int			i_attlen;
11083 	int			i_attalign;
11084 	int			i_attisdropped;
11085 	int			i_attcollation;
11086 	int			i;
11087 	int			actual_atts;
11088 
11089 	/* Fetch type specific details */
11090 	if (fout->remoteVersion >= 90100)
11091 	{
11092 		/*
11093 		 * attcollation is new in 9.1.  Since we only want to dump COLLATE
11094 		 * clauses for attributes whose collation is different from their
11095 		 * type's default, we use a CASE here to suppress uninteresting
11096 		 * attcollations cheaply.  atttypid will be 0 for dropped columns;
11097 		 * collation does not matter for those.
11098 		 */
11099 		appendPQExpBuffer(query, "SELECT a.attname, "
11100 						  "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
11101 						  "a.attlen, a.attalign, a.attisdropped, "
11102 						  "CASE WHEN a.attcollation <> at.typcollation "
11103 						  "THEN a.attcollation ELSE 0 END AS attcollation "
11104 						  "FROM pg_catalog.pg_type ct "
11105 						  "JOIN pg_catalog.pg_attribute a ON a.attrelid = ct.typrelid "
11106 						  "LEFT JOIN pg_catalog.pg_type at ON at.oid = a.atttypid "
11107 						  "WHERE ct.oid = '%u'::pg_catalog.oid "
11108 						  "ORDER BY a.attnum ",
11109 						  tyinfo->dobj.catId.oid);
11110 	}
11111 	else
11112 	{
11113 		/*
11114 		 * Since ALTER TYPE could not drop columns until 9.1, attisdropped
11115 		 * should always be false.
11116 		 */
11117 		appendPQExpBuffer(query, "SELECT a.attname, "
11118 						  "pg_catalog.format_type(a.atttypid, a.atttypmod) AS atttypdefn, "
11119 						  "a.attlen, a.attalign, a.attisdropped, "
11120 						  "0 AS attcollation "
11121 						  "FROM pg_catalog.pg_type ct, pg_catalog.pg_attribute a "
11122 						  "WHERE ct.oid = '%u'::pg_catalog.oid "
11123 						  "AND a.attrelid = ct.typrelid "
11124 						  "ORDER BY a.attnum ",
11125 						  tyinfo->dobj.catId.oid);
11126 	}
11127 
11128 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11129 
11130 	ntups = PQntuples(res);
11131 
11132 	i_attname = PQfnumber(res, "attname");
11133 	i_atttypdefn = PQfnumber(res, "atttypdefn");
11134 	i_attlen = PQfnumber(res, "attlen");
11135 	i_attalign = PQfnumber(res, "attalign");
11136 	i_attisdropped = PQfnumber(res, "attisdropped");
11137 	i_attcollation = PQfnumber(res, "attcollation");
11138 
11139 	if (dopt->binary_upgrade)
11140 	{
11141 		binary_upgrade_set_type_oids_by_type_oid(fout, q,
11142 												 tyinfo->dobj.catId.oid,
11143 												 false);
11144 		binary_upgrade_set_pg_class_oids(fout, q, tyinfo->typrelid, false);
11145 	}
11146 
11147 	qtypname = pg_strdup(fmtId(tyinfo->dobj.name));
11148 	qualtypname = pg_strdup(fmtQualifiedDumpable(tyinfo));
11149 
11150 	appendPQExpBuffer(q, "CREATE TYPE %s AS (",
11151 					  qualtypname);
11152 
11153 	actual_atts = 0;
11154 	for (i = 0; i < ntups; i++)
11155 	{
11156 		char	   *attname;
11157 		char	   *atttypdefn;
11158 		char	   *attlen;
11159 		char	   *attalign;
11160 		bool		attisdropped;
11161 		Oid			attcollation;
11162 
11163 		attname = PQgetvalue(res, i, i_attname);
11164 		atttypdefn = PQgetvalue(res, i, i_atttypdefn);
11165 		attlen = PQgetvalue(res, i, i_attlen);
11166 		attalign = PQgetvalue(res, i, i_attalign);
11167 		attisdropped = (PQgetvalue(res, i, i_attisdropped)[0] == 't');
11168 		attcollation = atooid(PQgetvalue(res, i, i_attcollation));
11169 
11170 		if (attisdropped && !dopt->binary_upgrade)
11171 			continue;
11172 
11173 		/* Format properly if not first attr */
11174 		if (actual_atts++ > 0)
11175 			appendPQExpBufferChar(q, ',');
11176 		appendPQExpBufferStr(q, "\n\t");
11177 
11178 		if (!attisdropped)
11179 		{
11180 			appendPQExpBuffer(q, "%s %s", fmtId(attname), atttypdefn);
11181 
11182 			/* Add collation if not default for the column type */
11183 			if (OidIsValid(attcollation))
11184 			{
11185 				CollInfo   *coll;
11186 
11187 				coll = findCollationByOid(attcollation);
11188 				if (coll)
11189 					appendPQExpBuffer(q, " COLLATE %s",
11190 									  fmtQualifiedDumpable(coll));
11191 			}
11192 		}
11193 		else
11194 		{
11195 			/*
11196 			 * This is a dropped attribute and we're in binary_upgrade mode.
11197 			 * Insert a placeholder for it in the CREATE TYPE command, and set
11198 			 * length and alignment with direct UPDATE to the catalogs
11199 			 * afterwards. See similar code in dumpTableSchema().
11200 			 */
11201 			appendPQExpBuffer(q, "%s INTEGER /* dummy */", fmtId(attname));
11202 
11203 			/* stash separately for insertion after the CREATE TYPE */
11204 			appendPQExpBufferStr(dropped,
11205 								 "\n-- For binary upgrade, recreate dropped column.\n");
11206 			appendPQExpBuffer(dropped, "UPDATE pg_catalog.pg_attribute\n"
11207 							  "SET attlen = %s, "
11208 							  "attalign = '%s', attbyval = false\n"
11209 							  "WHERE attname = ", attlen, attalign);
11210 			appendStringLiteralAH(dropped, attname, fout);
11211 			appendPQExpBufferStr(dropped, "\n  AND attrelid = ");
11212 			appendStringLiteralAH(dropped, qualtypname, fout);
11213 			appendPQExpBufferStr(dropped, "::pg_catalog.regclass;\n");
11214 
11215 			appendPQExpBuffer(dropped, "ALTER TYPE %s ",
11216 							  qualtypname);
11217 			appendPQExpBuffer(dropped, "DROP ATTRIBUTE %s;\n",
11218 							  fmtId(attname));
11219 		}
11220 	}
11221 	appendPQExpBufferStr(q, "\n);\n");
11222 	appendPQExpBufferStr(q, dropped->data);
11223 
11224 	appendPQExpBuffer(delq, "DROP TYPE %s;\n", qualtypname);
11225 
11226 	if (dopt->binary_upgrade)
11227 		binary_upgrade_extension_member(q, &tyinfo->dobj,
11228 										"TYPE", qtypname,
11229 										tyinfo->dobj.namespace->dobj.name);
11230 
11231 	if (tyinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11232 		ArchiveEntry(fout, tyinfo->dobj.catId, tyinfo->dobj.dumpId,
11233 					 tyinfo->dobj.name,
11234 					 tyinfo->dobj.namespace->dobj.name,
11235 					 NULL,
11236 					 tyinfo->rolname, false,
11237 					 "TYPE", SECTION_PRE_DATA,
11238 					 q->data, delq->data, NULL,
11239 					 NULL, 0,
11240 					 NULL, NULL);
11241 
11242 
11243 	/* Dump Type Comments and Security Labels */
11244 	if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
11245 		dumpComment(fout, "TYPE", qtypname,
11246 					tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11247 					tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11248 
11249 	if (tyinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
11250 		dumpSecLabel(fout, "TYPE", qtypname,
11251 					 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
11252 					 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
11253 
11254 	if (tyinfo->dobj.dump & DUMP_COMPONENT_ACL)
11255 		dumpACL(fout, tyinfo->dobj.dumpId, InvalidDumpId, "TYPE",
11256 				qtypname, NULL,
11257 				tyinfo->dobj.namespace->dobj.name,
11258 				tyinfo->rolname, tyinfo->typacl, tyinfo->rtypacl,
11259 				tyinfo->inittypacl, tyinfo->initrtypacl);
11260 
11261 	PQclear(res);
11262 	destroyPQExpBuffer(q);
11263 	destroyPQExpBuffer(dropped);
11264 	destroyPQExpBuffer(delq);
11265 	destroyPQExpBuffer(query);
11266 	free(qtypname);
11267 	free(qualtypname);
11268 
11269 	/* Dump any per-column comments */
11270 	if (tyinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
11271 		dumpCompositeTypeColComments(fout, tyinfo);
11272 }
11273 
11274 /*
11275  * dumpCompositeTypeColComments
11276  *	  writes out to fout the queries to recreate comments on the columns of
11277  *	  a user-defined stand-alone composite type
11278  */
11279 static void
dumpCompositeTypeColComments(Archive * fout,TypeInfo * tyinfo)11280 dumpCompositeTypeColComments(Archive *fout, TypeInfo *tyinfo)
11281 {
11282 	CommentItem *comments;
11283 	int			ncomments;
11284 	PGresult   *res;
11285 	PQExpBuffer query;
11286 	PQExpBuffer target;
11287 	Oid			pgClassOid;
11288 	int			i;
11289 	int			ntups;
11290 	int			i_attname;
11291 	int			i_attnum;
11292 
11293 	/* do nothing, if --no-comments is supplied */
11294 	if (fout->dopt->no_comments)
11295 		return;
11296 
11297 	query = createPQExpBuffer();
11298 
11299 	appendPQExpBuffer(query,
11300 					  "SELECT c.tableoid, a.attname, a.attnum "
11301 					  "FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a "
11302 					  "WHERE c.oid = '%u' AND c.oid = a.attrelid "
11303 					  "  AND NOT a.attisdropped "
11304 					  "ORDER BY a.attnum ",
11305 					  tyinfo->typrelid);
11306 
11307 	/* Fetch column attnames */
11308 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
11309 
11310 	ntups = PQntuples(res);
11311 	if (ntups < 1)
11312 	{
11313 		PQclear(res);
11314 		destroyPQExpBuffer(query);
11315 		return;
11316 	}
11317 
11318 	pgClassOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "tableoid")));
11319 
11320 	/* Search for comments associated with type's pg_class OID */
11321 	ncomments = findComments(fout,
11322 							 pgClassOid,
11323 							 tyinfo->typrelid,
11324 							 &comments);
11325 
11326 	/* If no comments exist, we're done */
11327 	if (ncomments <= 0)
11328 	{
11329 		PQclear(res);
11330 		destroyPQExpBuffer(query);
11331 		return;
11332 	}
11333 
11334 	/* Build COMMENT ON statements */
11335 	target = createPQExpBuffer();
11336 
11337 	i_attnum = PQfnumber(res, "attnum");
11338 	i_attname = PQfnumber(res, "attname");
11339 	while (ncomments > 0)
11340 	{
11341 		const char *attname;
11342 
11343 		attname = NULL;
11344 		for (i = 0; i < ntups; i++)
11345 		{
11346 			if (atoi(PQgetvalue(res, i, i_attnum)) == comments->objsubid)
11347 			{
11348 				attname = PQgetvalue(res, i, i_attname);
11349 				break;
11350 			}
11351 		}
11352 		if (attname)			/* just in case we don't find it */
11353 		{
11354 			const char *descr = comments->descr;
11355 
11356 			resetPQExpBuffer(target);
11357 			appendPQExpBuffer(target, "COLUMN %s.",
11358 							  fmtId(tyinfo->dobj.name));
11359 			appendPQExpBufferStr(target, fmtId(attname));
11360 
11361 			resetPQExpBuffer(query);
11362 			appendPQExpBuffer(query, "COMMENT ON COLUMN %s.",
11363 							  fmtQualifiedDumpable(tyinfo));
11364 			appendPQExpBuffer(query, "%s IS ", fmtId(attname));
11365 			appendStringLiteralAH(query, descr, fout);
11366 			appendPQExpBufferStr(query, ";\n");
11367 
11368 			ArchiveEntry(fout, nilCatalogId, createDumpId(),
11369 						 target->data,
11370 						 tyinfo->dobj.namespace->dobj.name,
11371 						 NULL, tyinfo->rolname,
11372 						 false, "COMMENT", SECTION_NONE,
11373 						 query->data, "", NULL,
11374 						 &(tyinfo->dobj.dumpId), 1,
11375 						 NULL, NULL);
11376 		}
11377 
11378 		comments++;
11379 		ncomments--;
11380 	}
11381 
11382 	PQclear(res);
11383 	destroyPQExpBuffer(query);
11384 	destroyPQExpBuffer(target);
11385 }
11386 
11387 /*
11388  * dumpShellType
11389  *	  writes out to fout the queries to create a shell type
11390  *
11391  * We dump a shell definition in advance of the I/O functions for the type.
11392  */
11393 static void
dumpShellType(Archive * fout,ShellTypeInfo * stinfo)11394 dumpShellType(Archive *fout, ShellTypeInfo *stinfo)
11395 {
11396 	DumpOptions *dopt = fout->dopt;
11397 	PQExpBuffer q;
11398 
11399 	/* Skip if not to be dumped */
11400 	if (!stinfo->dobj.dump || dopt->dataOnly)
11401 		return;
11402 
11403 	q = createPQExpBuffer();
11404 
11405 	/*
11406 	 * Note the lack of a DROP command for the shell type; any required DROP
11407 	 * is driven off the base type entry, instead.  This interacts with
11408 	 * _printTocEntry()'s use of the presence of a DROP command to decide
11409 	 * whether an entry needs an ALTER OWNER command.  We don't want to alter
11410 	 * the shell type's owner immediately on creation; that should happen only
11411 	 * after it's filled in, otherwise the backend complains.
11412 	 */
11413 
11414 	if (dopt->binary_upgrade)
11415 		binary_upgrade_set_type_oids_by_type_oid(fout, q,
11416 												 stinfo->baseType->dobj.catId.oid,
11417 												 false);
11418 
11419 	appendPQExpBuffer(q, "CREATE TYPE %s;\n",
11420 					  fmtQualifiedDumpable(stinfo));
11421 
11422 	if (stinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
11423 		ArchiveEntry(fout, stinfo->dobj.catId, stinfo->dobj.dumpId,
11424 					 stinfo->dobj.name,
11425 					 stinfo->dobj.namespace->dobj.name,
11426 					 NULL,
11427 					 stinfo->baseType->rolname, false,
11428 					 "SHELL TYPE", SECTION_PRE_DATA,
11429 					 q->data, "", NULL,
11430 					 NULL, 0,
11431 					 NULL, NULL);
11432 
11433 	destroyPQExpBuffer(q);
11434 }
11435 
11436 /*
11437  * dumpProcLang
11438  *		  writes out to fout the queries to recreate a user-defined
11439  *		  procedural language
11440  */
11441 static void
dumpProcLang(Archive * fout,ProcLangInfo * plang)11442 dumpProcLang(Archive *fout, ProcLangInfo *plang)
11443 {
11444 	DumpOptions *dopt = fout->dopt;
11445 	PQExpBuffer defqry;
11446 	PQExpBuffer delqry;
11447 	bool		useParams;
11448 	char	   *qlanname;
11449 	FuncInfo   *funcInfo;
11450 	FuncInfo   *inlineInfo = NULL;
11451 	FuncInfo   *validatorInfo = NULL;
11452 
11453 	/* Skip if not to be dumped */
11454 	if (!plang->dobj.dump || dopt->dataOnly)
11455 		return;
11456 
11457 	/*
11458 	 * Try to find the support function(s).  It is not an error if we don't
11459 	 * find them --- if the functions are in the pg_catalog schema, as is
11460 	 * standard in 8.1 and up, then we won't have loaded them. (In this case
11461 	 * we will emit a parameterless CREATE LANGUAGE command, which will
11462 	 * require PL template knowledge in the backend to reload.)
11463 	 */
11464 
11465 	funcInfo = findFuncByOid(plang->lanplcallfoid);
11466 	if (funcInfo != NULL && !funcInfo->dobj.dump)
11467 		funcInfo = NULL;		/* treat not-dumped same as not-found */
11468 
11469 	if (OidIsValid(plang->laninline))
11470 	{
11471 		inlineInfo = findFuncByOid(plang->laninline);
11472 		if (inlineInfo != NULL && !inlineInfo->dobj.dump)
11473 			inlineInfo = NULL;
11474 	}
11475 
11476 	if (OidIsValid(plang->lanvalidator))
11477 	{
11478 		validatorInfo = findFuncByOid(plang->lanvalidator);
11479 		if (validatorInfo != NULL && !validatorInfo->dobj.dump)
11480 			validatorInfo = NULL;
11481 	}
11482 
11483 	/*
11484 	 * If the functions are dumpable then emit a traditional CREATE LANGUAGE
11485 	 * with parameters.  Otherwise, we'll write a parameterless command, which
11486 	 * will rely on data from pg_pltemplate.
11487 	 */
11488 	useParams = (funcInfo != NULL &&
11489 				 (inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
11490 				 (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
11491 
11492 	defqry = createPQExpBuffer();
11493 	delqry = createPQExpBuffer();
11494 
11495 	qlanname = pg_strdup(fmtId(plang->dobj.name));
11496 
11497 	appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n",
11498 					  qlanname);
11499 
11500 	if (useParams)
11501 	{
11502 		appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
11503 						  plang->lanpltrusted ? "TRUSTED " : "",
11504 						  qlanname);
11505 		appendPQExpBuffer(defqry, " HANDLER %s",
11506 						  fmtQualifiedDumpable(funcInfo));
11507 		if (OidIsValid(plang->laninline))
11508 			appendPQExpBuffer(defqry, " INLINE %s",
11509 							  fmtQualifiedDumpable(inlineInfo));
11510 		if (OidIsValid(plang->lanvalidator))
11511 			appendPQExpBuffer(defqry, " VALIDATOR %s",
11512 							  fmtQualifiedDumpable(validatorInfo));
11513 	}
11514 	else
11515 	{
11516 		/*
11517 		 * If not dumping parameters, then use CREATE OR REPLACE so that the
11518 		 * command will not fail if the language is preinstalled in the target
11519 		 * database.  We restrict the use of REPLACE to this case so as to
11520 		 * eliminate the risk of replacing a language with incompatible
11521 		 * parameter settings: this command will only succeed at all if there
11522 		 * is a pg_pltemplate entry, and if there is one, the existing entry
11523 		 * must match it too.
11524 		 */
11525 		appendPQExpBuffer(defqry, "CREATE OR REPLACE PROCEDURAL LANGUAGE %s",
11526 						  qlanname);
11527 	}
11528 	appendPQExpBufferStr(defqry, ";\n");
11529 
11530 	if (dopt->binary_upgrade)
11531 		binary_upgrade_extension_member(defqry, &plang->dobj,
11532 										"LANGUAGE", qlanname, NULL);
11533 
11534 	if (plang->dobj.dump & DUMP_COMPONENT_DEFINITION)
11535 		ArchiveEntry(fout, plang->dobj.catId, plang->dobj.dumpId,
11536 					 plang->dobj.name,
11537 					 NULL, NULL, plang->lanowner,
11538 					 false, "PROCEDURAL LANGUAGE", SECTION_PRE_DATA,
11539 					 defqry->data, delqry->data, NULL,
11540 					 NULL, 0,
11541 					 NULL, NULL);
11542 
11543 	/* Dump Proc Lang Comments and Security Labels */
11544 	if (plang->dobj.dump & DUMP_COMPONENT_COMMENT)
11545 		dumpComment(fout, "LANGUAGE", qlanname,
11546 					NULL, plang->lanowner,
11547 					plang->dobj.catId, 0, plang->dobj.dumpId);
11548 
11549 	if (plang->dobj.dump & DUMP_COMPONENT_SECLABEL)
11550 		dumpSecLabel(fout, "LANGUAGE", qlanname,
11551 					 NULL, plang->lanowner,
11552 					 plang->dobj.catId, 0, plang->dobj.dumpId);
11553 
11554 	if (plang->lanpltrusted && plang->dobj.dump & DUMP_COMPONENT_ACL)
11555 		dumpACL(fout, plang->dobj.dumpId, InvalidDumpId, "LANGUAGE",
11556 				qlanname, NULL, NULL,
11557 				plang->lanowner, plang->lanacl, plang->rlanacl,
11558 				plang->initlanacl, plang->initrlanacl);
11559 
11560 	free(qlanname);
11561 
11562 	destroyPQExpBuffer(defqry);
11563 	destroyPQExpBuffer(delqry);
11564 }
11565 
11566 /*
11567  * format_function_arguments: generate function name and argument list
11568  *
11569  * This is used when we can rely on pg_get_function_arguments to format
11570  * the argument list.  Note, however, that pg_get_function_arguments
11571  * does not special-case zero-argument aggregates.
11572  */
11573 static char *
format_function_arguments(FuncInfo * finfo,char * funcargs,bool is_agg)11574 format_function_arguments(FuncInfo *finfo, char *funcargs, bool is_agg)
11575 {
11576 	PQExpBufferData fn;
11577 
11578 	initPQExpBuffer(&fn);
11579 	appendPQExpBufferStr(&fn, fmtId(finfo->dobj.name));
11580 	if (is_agg && finfo->nargs == 0)
11581 		appendPQExpBufferStr(&fn, "(*)");
11582 	else
11583 		appendPQExpBuffer(&fn, "(%s)", funcargs);
11584 	return fn.data;
11585 }
11586 
11587 /*
11588  * format_function_arguments_old: generate function name and argument list
11589  *
11590  * The argument type names are qualified if needed.  The function name
11591  * is never qualified.
11592  *
11593  * This is used only with pre-8.4 servers, so we aren't expecting to see
11594  * VARIADIC or TABLE arguments, nor are there any defaults for arguments.
11595  *
11596  * Any or all of allargtypes, argmodes, argnames may be NULL.
11597  */
11598 static char *
format_function_arguments_old(Archive * fout,FuncInfo * finfo,int nallargs,char ** allargtypes,char ** argmodes,char ** argnames)11599 format_function_arguments_old(Archive *fout,
11600 							  FuncInfo *finfo, int nallargs,
11601 							  char **allargtypes,
11602 							  char **argmodes,
11603 							  char **argnames)
11604 {
11605 	PQExpBufferData fn;
11606 	int			j;
11607 
11608 	initPQExpBuffer(&fn);
11609 	appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
11610 	for (j = 0; j < nallargs; j++)
11611 	{
11612 		Oid			typid;
11613 		const char *typname;
11614 		const char *argmode;
11615 		const char *argname;
11616 
11617 		typid = allargtypes ? atooid(allargtypes[j]) : finfo->argtypes[j];
11618 		typname = getFormattedTypeName(fout, typid, zeroAsOpaque);
11619 
11620 		if (argmodes)
11621 		{
11622 			switch (argmodes[j][0])
11623 			{
11624 				case PROARGMODE_IN:
11625 					argmode = "";
11626 					break;
11627 				case PROARGMODE_OUT:
11628 					argmode = "OUT ";
11629 					break;
11630 				case PROARGMODE_INOUT:
11631 					argmode = "INOUT ";
11632 					break;
11633 				default:
11634 					write_msg(NULL, "WARNING: bogus value in proargmodes array\n");
11635 					argmode = "";
11636 					break;
11637 			}
11638 		}
11639 		else
11640 			argmode = "";
11641 
11642 		argname = argnames ? argnames[j] : (char *) NULL;
11643 		if (argname && argname[0] == '\0')
11644 			argname = NULL;
11645 
11646 		appendPQExpBuffer(&fn, "%s%s%s%s%s",
11647 						  (j > 0) ? ", " : "",
11648 						  argmode,
11649 						  argname ? fmtId(argname) : "",
11650 						  argname ? " " : "",
11651 						  typname);
11652 	}
11653 	appendPQExpBufferChar(&fn, ')');
11654 	return fn.data;
11655 }
11656 
11657 /*
11658  * format_function_signature: generate function name and argument list
11659  *
11660  * This is like format_function_arguments_old except that only a minimal
11661  * list of input argument types is generated; this is sufficient to
11662  * reference the function, but not to define it.
11663  *
11664  * If honor_quotes is false then the function name is never quoted.
11665  * This is appropriate for use in TOC tags, but not in SQL commands.
11666  */
11667 static char *
format_function_signature(Archive * fout,FuncInfo * finfo,bool honor_quotes)11668 format_function_signature(Archive *fout, FuncInfo *finfo, bool honor_quotes)
11669 {
11670 	PQExpBufferData fn;
11671 	int			j;
11672 
11673 	initPQExpBuffer(&fn);
11674 	if (honor_quotes)
11675 		appendPQExpBuffer(&fn, "%s(", fmtId(finfo->dobj.name));
11676 	else
11677 		appendPQExpBuffer(&fn, "%s(", finfo->dobj.name);
11678 	for (j = 0; j < finfo->nargs; j++)
11679 	{
11680 		if (j > 0)
11681 			appendPQExpBufferStr(&fn, ", ");
11682 
11683 		appendPQExpBufferStr(&fn,
11684 							 getFormattedTypeName(fout, finfo->argtypes[j],
11685 												  zeroAsOpaque));
11686 	}
11687 	appendPQExpBufferChar(&fn, ')');
11688 	return fn.data;
11689 }
11690 
11691 
11692 /*
11693  * dumpFunc:
11694  *	  dump out one function
11695  */
11696 static void
dumpFunc(Archive * fout,FuncInfo * finfo)11697 dumpFunc(Archive *fout, FuncInfo *finfo)
11698 {
11699 	DumpOptions *dopt = fout->dopt;
11700 	PQExpBuffer query;
11701 	PQExpBuffer q;
11702 	PQExpBuffer delqry;
11703 	PQExpBuffer asPart;
11704 	PGresult   *res;
11705 	char	   *funcsig;		/* identity signature */
11706 	char	   *funcfullsig = NULL; /* full signature */
11707 	char	   *funcsig_tag;
11708 	char	   *proretset;
11709 	char	   *prosrc;
11710 	char	   *probin;
11711 	char	   *funcargs;
11712 	char	   *funciargs;
11713 	char	   *funcresult;
11714 	char	   *proallargtypes;
11715 	char	   *proargmodes;
11716 	char	   *proargnames;
11717 	char	   *protrftypes;
11718 	char	   *prokind;
11719 	char	   *provolatile;
11720 	char	   *proisstrict;
11721 	char	   *prosecdef;
11722 	char	   *proleakproof;
11723 	char	   *proconfig;
11724 	char	   *procost;
11725 	char	   *prorows;
11726 	char	   *proparallel;
11727 	char	   *lanname;
11728 	int			nallargs;
11729 	char	  **allargtypes = NULL;
11730 	char	  **argmodes = NULL;
11731 	char	  **argnames = NULL;
11732 	char	  **configitems = NULL;
11733 	int			nconfigitems = 0;
11734 	const char *keyword;
11735 	int			i;
11736 
11737 	/* Skip if not to be dumped */
11738 	if (!finfo->dobj.dump || dopt->dataOnly)
11739 		return;
11740 
11741 	query = createPQExpBuffer();
11742 	q = createPQExpBuffer();
11743 	delqry = createPQExpBuffer();
11744 	asPart = createPQExpBuffer();
11745 
11746 	/* Fetch function-specific details */
11747 	if (fout->remoteVersion >= 110000)
11748 	{
11749 		/*
11750 		 * prokind was added in 11
11751 		 */
11752 		appendPQExpBuffer(query,
11753 						  "SELECT proretset, prosrc, probin, "
11754 						  "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11755 						  "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11756 						  "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11757 						  "array_to_string(protrftypes, ' ') AS protrftypes, "
11758 						  "prokind, provolatile, proisstrict, prosecdef, "
11759 						  "proleakproof, proconfig, procost, prorows, "
11760 						  "proparallel, "
11761 						  "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11762 						  "FROM pg_catalog.pg_proc "
11763 						  "WHERE oid = '%u'::pg_catalog.oid",
11764 						  finfo->dobj.catId.oid);
11765 	}
11766 	else if (fout->remoteVersion >= 90600)
11767 	{
11768 		/*
11769 		 * proparallel was added in 9.6
11770 		 */
11771 		appendPQExpBuffer(query,
11772 						  "SELECT proretset, prosrc, probin, "
11773 						  "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11774 						  "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11775 						  "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11776 						  "array_to_string(protrftypes, ' ') AS protrftypes, "
11777 						  "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
11778 						  "provolatile, proisstrict, prosecdef, "
11779 						  "proleakproof, proconfig, procost, prorows, "
11780 						  "proparallel, "
11781 						  "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11782 						  "FROM pg_catalog.pg_proc "
11783 						  "WHERE oid = '%u'::pg_catalog.oid",
11784 						  finfo->dobj.catId.oid);
11785 	}
11786 	else if (fout->remoteVersion >= 90500)
11787 	{
11788 		/*
11789 		 * protrftypes was added in 9.5
11790 		 */
11791 		appendPQExpBuffer(query,
11792 						  "SELECT proretset, prosrc, probin, "
11793 						  "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11794 						  "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11795 						  "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11796 						  "array_to_string(protrftypes, ' ') AS protrftypes, "
11797 						  "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
11798 						  "provolatile, proisstrict, prosecdef, "
11799 						  "proleakproof, proconfig, procost, prorows, "
11800 						  "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11801 						  "FROM pg_catalog.pg_proc "
11802 						  "WHERE oid = '%u'::pg_catalog.oid",
11803 						  finfo->dobj.catId.oid);
11804 	}
11805 	else if (fout->remoteVersion >= 90200)
11806 	{
11807 		/*
11808 		 * proleakproof was added in 9.2
11809 		 */
11810 		appendPQExpBuffer(query,
11811 						  "SELECT proretset, prosrc, probin, "
11812 						  "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11813 						  "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11814 						  "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11815 						  "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
11816 						  "provolatile, proisstrict, prosecdef, "
11817 						  "proleakproof, proconfig, procost, prorows, "
11818 						  "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11819 						  "FROM pg_catalog.pg_proc "
11820 						  "WHERE oid = '%u'::pg_catalog.oid",
11821 						  finfo->dobj.catId.oid);
11822 	}
11823 	else if (fout->remoteVersion >= 80400)
11824 	{
11825 		/*
11826 		 * In 8.4 and up we rely on pg_get_function_arguments and
11827 		 * pg_get_function_result instead of examining proallargtypes etc.
11828 		 */
11829 		appendPQExpBuffer(query,
11830 						  "SELECT proretset, prosrc, probin, "
11831 						  "pg_catalog.pg_get_function_arguments(oid) AS funcargs, "
11832 						  "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
11833 						  "pg_catalog.pg_get_function_result(oid) AS funcresult, "
11834 						  "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
11835 						  "provolatile, proisstrict, prosecdef, "
11836 						  "false AS proleakproof, "
11837 						  " proconfig, procost, prorows, "
11838 						  "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11839 						  "FROM pg_catalog.pg_proc "
11840 						  "WHERE oid = '%u'::pg_catalog.oid",
11841 						  finfo->dobj.catId.oid);
11842 	}
11843 	else if (fout->remoteVersion >= 80300)
11844 	{
11845 		appendPQExpBuffer(query,
11846 						  "SELECT proretset, prosrc, probin, "
11847 						  "proallargtypes, proargmodes, proargnames, "
11848 						  "'f' AS prokind, "
11849 						  "provolatile, proisstrict, prosecdef, "
11850 						  "false AS proleakproof, "
11851 						  "proconfig, procost, prorows, "
11852 						  "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11853 						  "FROM pg_catalog.pg_proc "
11854 						  "WHERE oid = '%u'::pg_catalog.oid",
11855 						  finfo->dobj.catId.oid);
11856 	}
11857 	else if (fout->remoteVersion >= 80100)
11858 	{
11859 		appendPQExpBuffer(query,
11860 						  "SELECT proretset, prosrc, probin, "
11861 						  "proallargtypes, proargmodes, proargnames, "
11862 						  "'f' AS prokind, "
11863 						  "provolatile, proisstrict, prosecdef, "
11864 						  "false AS proleakproof, "
11865 						  "null AS proconfig, 0 AS procost, 0 AS prorows, "
11866 						  "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11867 						  "FROM pg_catalog.pg_proc "
11868 						  "WHERE oid = '%u'::pg_catalog.oid",
11869 						  finfo->dobj.catId.oid);
11870 	}
11871 	else
11872 	{
11873 		appendPQExpBuffer(query,
11874 						  "SELECT proretset, prosrc, probin, "
11875 						  "null AS proallargtypes, "
11876 						  "null AS proargmodes, "
11877 						  "proargnames, "
11878 						  "'f' AS prokind, "
11879 						  "provolatile, proisstrict, prosecdef, "
11880 						  "false AS proleakproof, "
11881 						  "null AS proconfig, 0 AS procost, 0 AS prorows, "
11882 						  "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
11883 						  "FROM pg_catalog.pg_proc "
11884 						  "WHERE oid = '%u'::pg_catalog.oid",
11885 						  finfo->dobj.catId.oid);
11886 	}
11887 
11888 	res = ExecuteSqlQueryForSingleRow(fout, query->data);
11889 
11890 	proretset = PQgetvalue(res, 0, PQfnumber(res, "proretset"));
11891 	prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
11892 	probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
11893 	if (fout->remoteVersion >= 80400)
11894 	{
11895 		funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
11896 		funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
11897 		funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
11898 		proallargtypes = proargmodes = proargnames = NULL;
11899 	}
11900 	else
11901 	{
11902 		proallargtypes = PQgetvalue(res, 0, PQfnumber(res, "proallargtypes"));
11903 		proargmodes = PQgetvalue(res, 0, PQfnumber(res, "proargmodes"));
11904 		proargnames = PQgetvalue(res, 0, PQfnumber(res, "proargnames"));
11905 		funcargs = funciargs = funcresult = NULL;
11906 	}
11907 	if (PQfnumber(res, "protrftypes") != -1)
11908 		protrftypes = PQgetvalue(res, 0, PQfnumber(res, "protrftypes"));
11909 	else
11910 		protrftypes = NULL;
11911 	prokind = PQgetvalue(res, 0, PQfnumber(res, "prokind"));
11912 	provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
11913 	proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
11914 	prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
11915 	proleakproof = PQgetvalue(res, 0, PQfnumber(res, "proleakproof"));
11916 	proconfig = PQgetvalue(res, 0, PQfnumber(res, "proconfig"));
11917 	procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
11918 	prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
11919 
11920 	if (PQfnumber(res, "proparallel") != -1)
11921 		proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
11922 	else
11923 		proparallel = NULL;
11924 
11925 	lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
11926 
11927 	/*
11928 	 * See backend/commands/functioncmds.c for details of how the 'AS' clause
11929 	 * is used.  In 8.4 and up, an unused probin is NULL (here ""); previous
11930 	 * versions would set it to "-".  There are no known cases in which prosrc
11931 	 * is unused, so the tests below for "-" are probably useless.
11932 	 */
11933 	if (probin[0] != '\0' && strcmp(probin, "-") != 0)
11934 	{
11935 		appendPQExpBufferStr(asPart, "AS ");
11936 		appendStringLiteralAH(asPart, probin, fout);
11937 		if (strcmp(prosrc, "-") != 0)
11938 		{
11939 			appendPQExpBufferStr(asPart, ", ");
11940 
11941 			/*
11942 			 * where we have bin, use dollar quoting if allowed and src
11943 			 * contains quote or backslash; else use regular quoting.
11944 			 */
11945 			if (dopt->disable_dollar_quoting ||
11946 				(strchr(prosrc, '\'') == NULL && strchr(prosrc, '\\') == NULL))
11947 				appendStringLiteralAH(asPart, prosrc, fout);
11948 			else
11949 				appendStringLiteralDQ(asPart, prosrc, NULL);
11950 		}
11951 	}
11952 	else
11953 	{
11954 		if (strcmp(prosrc, "-") != 0)
11955 		{
11956 			appendPQExpBufferStr(asPart, "AS ");
11957 			/* with no bin, dollar quote src unconditionally if allowed */
11958 			if (dopt->disable_dollar_quoting)
11959 				appendStringLiteralAH(asPart, prosrc, fout);
11960 			else
11961 				appendStringLiteralDQ(asPart, prosrc, NULL);
11962 		}
11963 	}
11964 
11965 	nallargs = finfo->nargs;	/* unless we learn different from allargs */
11966 
11967 	if (proallargtypes && *proallargtypes)
11968 	{
11969 		int			nitems = 0;
11970 
11971 		if (!parsePGArray(proallargtypes, &allargtypes, &nitems) ||
11972 			nitems < finfo->nargs)
11973 		{
11974 			write_msg(NULL, "WARNING: could not parse proallargtypes array\n");
11975 			if (allargtypes)
11976 				free(allargtypes);
11977 			allargtypes = NULL;
11978 		}
11979 		else
11980 			nallargs = nitems;
11981 	}
11982 
11983 	if (proargmodes && *proargmodes)
11984 	{
11985 		int			nitems = 0;
11986 
11987 		if (!parsePGArray(proargmodes, &argmodes, &nitems) ||
11988 			nitems != nallargs)
11989 		{
11990 			write_msg(NULL, "WARNING: could not parse proargmodes array\n");
11991 			if (argmodes)
11992 				free(argmodes);
11993 			argmodes = NULL;
11994 		}
11995 	}
11996 
11997 	if (proargnames && *proargnames)
11998 	{
11999 		int			nitems = 0;
12000 
12001 		if (!parsePGArray(proargnames, &argnames, &nitems) ||
12002 			nitems != nallargs)
12003 		{
12004 			write_msg(NULL, "WARNING: could not parse proargnames array\n");
12005 			if (argnames)
12006 				free(argnames);
12007 			argnames = NULL;
12008 		}
12009 	}
12010 
12011 	if (proconfig && *proconfig)
12012 	{
12013 		if (!parsePGArray(proconfig, &configitems, &nconfigitems))
12014 		{
12015 			write_msg(NULL, "WARNING: could not parse proconfig array\n");
12016 			if (configitems)
12017 				free(configitems);
12018 			configitems = NULL;
12019 			nconfigitems = 0;
12020 		}
12021 	}
12022 
12023 	if (funcargs)
12024 	{
12025 		/* 8.4 or later; we rely on server-side code for most of the work */
12026 		funcfullsig = format_function_arguments(finfo, funcargs, false);
12027 		funcsig = format_function_arguments(finfo, funciargs, false);
12028 	}
12029 	else
12030 		/* pre-8.4, do it ourselves */
12031 		funcsig = format_function_arguments_old(fout,
12032 												finfo, nallargs, allargtypes,
12033 												argmodes, argnames);
12034 
12035 	funcsig_tag = format_function_signature(fout, finfo, false);
12036 
12037 	if (prokind[0] == PROKIND_PROCEDURE)
12038 		keyword = "PROCEDURE";
12039 	else
12040 		keyword = "FUNCTION";	/* works for window functions too */
12041 
12042 	appendPQExpBuffer(delqry, "DROP %s %s.%s;\n",
12043 					  keyword,
12044 					  fmtId(finfo->dobj.namespace->dobj.name),
12045 					  funcsig);
12046 
12047 	appendPQExpBuffer(q, "CREATE %s %s.%s",
12048 					  keyword,
12049 					  fmtId(finfo->dobj.namespace->dobj.name),
12050 					  funcfullsig ? funcfullsig :
12051 					  funcsig);
12052 
12053 	if (prokind[0] == PROKIND_PROCEDURE)
12054 		 /* no result type to output */ ;
12055 	else if (funcresult)
12056 		appendPQExpBuffer(q, " RETURNS %s", funcresult);
12057 	else
12058 		appendPQExpBuffer(q, " RETURNS %s%s",
12059 						  (proretset[0] == 't') ? "SETOF " : "",
12060 						  getFormattedTypeName(fout, finfo->prorettype,
12061 											   zeroAsOpaque));
12062 
12063 	appendPQExpBuffer(q, "\n    LANGUAGE %s", fmtId(lanname));
12064 
12065 	if (protrftypes != NULL && strcmp(protrftypes, "") != 0)
12066 	{
12067 		Oid		   *typeids = palloc(FUNC_MAX_ARGS * sizeof(Oid));
12068 		int			i;
12069 
12070 		appendPQExpBufferStr(q, " TRANSFORM ");
12071 		parseOidArray(protrftypes, typeids, FUNC_MAX_ARGS);
12072 		for (i = 0; typeids[i]; i++)
12073 		{
12074 			if (i != 0)
12075 				appendPQExpBufferStr(q, ", ");
12076 			appendPQExpBuffer(q, "FOR TYPE %s",
12077 							  getFormattedTypeName(fout, typeids[i], zeroAsNone));
12078 		}
12079 	}
12080 
12081 	if (prokind[0] == PROKIND_WINDOW)
12082 		appendPQExpBufferStr(q, " WINDOW");
12083 
12084 	if (provolatile[0] != PROVOLATILE_VOLATILE)
12085 	{
12086 		if (provolatile[0] == PROVOLATILE_IMMUTABLE)
12087 			appendPQExpBufferStr(q, " IMMUTABLE");
12088 		else if (provolatile[0] == PROVOLATILE_STABLE)
12089 			appendPQExpBufferStr(q, " STABLE");
12090 		else if (provolatile[0] != PROVOLATILE_VOLATILE)
12091 			exit_horribly(NULL, "unrecognized provolatile value for function \"%s\"\n",
12092 						  finfo->dobj.name);
12093 	}
12094 
12095 	if (proisstrict[0] == 't')
12096 		appendPQExpBufferStr(q, " STRICT");
12097 
12098 	if (prosecdef[0] == 't')
12099 		appendPQExpBufferStr(q, " SECURITY DEFINER");
12100 
12101 	if (proleakproof[0] == 't')
12102 		appendPQExpBufferStr(q, " LEAKPROOF");
12103 
12104 	/*
12105 	 * COST and ROWS are emitted only if present and not default, so as not to
12106 	 * break backwards-compatibility of the dump without need.  Keep this code
12107 	 * in sync with the defaults in functioncmds.c.
12108 	 */
12109 	if (strcmp(procost, "0") != 0)
12110 	{
12111 		if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
12112 		{
12113 			/* default cost is 1 */
12114 			if (strcmp(procost, "1") != 0)
12115 				appendPQExpBuffer(q, " COST %s", procost);
12116 		}
12117 		else
12118 		{
12119 			/* default cost is 100 */
12120 			if (strcmp(procost, "100") != 0)
12121 				appendPQExpBuffer(q, " COST %s", procost);
12122 		}
12123 	}
12124 	if (proretset[0] == 't' &&
12125 		strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
12126 		appendPQExpBuffer(q, " ROWS %s", prorows);
12127 
12128 	if (proparallel != NULL && proparallel[0] != PROPARALLEL_UNSAFE)
12129 	{
12130 		if (proparallel[0] == PROPARALLEL_SAFE)
12131 			appendPQExpBufferStr(q, " PARALLEL SAFE");
12132 		else if (proparallel[0] == PROPARALLEL_RESTRICTED)
12133 			appendPQExpBufferStr(q, " PARALLEL RESTRICTED");
12134 		else if (proparallel[0] != PROPARALLEL_UNSAFE)
12135 			exit_horribly(NULL, "unrecognized proparallel value for function \"%s\"\n",
12136 						  finfo->dobj.name);
12137 	}
12138 
12139 	for (i = 0; i < nconfigitems; i++)
12140 	{
12141 		/* we feel free to scribble on configitems[] here */
12142 		char	   *configitem = configitems[i];
12143 		char	   *pos;
12144 
12145 		pos = strchr(configitem, '=');
12146 		if (pos == NULL)
12147 			continue;
12148 		*pos++ = '\0';
12149 		appendPQExpBuffer(q, "\n    SET %s TO ", fmtId(configitem));
12150 
12151 		/*
12152 		 * Variables that are marked GUC_LIST_QUOTE were already fully quoted
12153 		 * by flatten_set_variable_args() before they were put into the
12154 		 * proconfig array.  However, because the quoting rules used there
12155 		 * aren't exactly like SQL's, we have to break the list value apart
12156 		 * and then quote the elements as string literals.  (The elements may
12157 		 * be double-quoted as-is, but we can't just feed them to the SQL
12158 		 * parser; it would do the wrong thing with elements that are
12159 		 * zero-length or longer than NAMEDATALEN.)
12160 		 *
12161 		 * Variables that are not so marked should just be emitted as simple
12162 		 * string literals.  If the variable is not known to
12163 		 * variable_is_guc_list_quote(), we'll do that; this makes it unsafe
12164 		 * to use GUC_LIST_QUOTE for extension variables.
12165 		 */
12166 		if (variable_is_guc_list_quote(configitem))
12167 		{
12168 			char	  **namelist;
12169 			char	  **nameptr;
12170 
12171 			/* Parse string into list of identifiers */
12172 			/* this shouldn't fail really */
12173 			if (SplitGUCList(pos, ',', &namelist))
12174 			{
12175 				for (nameptr = namelist; *nameptr; nameptr++)
12176 				{
12177 					if (nameptr != namelist)
12178 						appendPQExpBufferStr(q, ", ");
12179 					appendStringLiteralAH(q, *nameptr, fout);
12180 				}
12181 			}
12182 			pg_free(namelist);
12183 		}
12184 		else
12185 			appendStringLiteralAH(q, pos, fout);
12186 	}
12187 
12188 	appendPQExpBuffer(q, "\n    %s;\n", asPart->data);
12189 
12190 	append_depends_on_extension(fout, q, &finfo->dobj,
12191 								"pg_catalog.pg_proc", keyword,
12192 								psprintf("%s.%s",
12193 										 fmtId(finfo->dobj.namespace->dobj.name),
12194 										 funcsig));
12195 
12196 	if (dopt->binary_upgrade)
12197 		binary_upgrade_extension_member(q, &finfo->dobj,
12198 										keyword, funcsig,
12199 										finfo->dobj.namespace->dobj.name);
12200 
12201 	if (finfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12202 		ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
12203 					 funcsig_tag,
12204 					 finfo->dobj.namespace->dobj.name,
12205 					 NULL,
12206 					 finfo->rolname, false,
12207 					 keyword, SECTION_PRE_DATA,
12208 					 q->data, delqry->data, NULL,
12209 					 NULL, 0,
12210 					 NULL, NULL);
12211 
12212 	/* Dump Function Comments and Security Labels */
12213 	if (finfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12214 		dumpComment(fout, keyword, funcsig,
12215 					finfo->dobj.namespace->dobj.name, finfo->rolname,
12216 					finfo->dobj.catId, 0, finfo->dobj.dumpId);
12217 
12218 	if (finfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
12219 		dumpSecLabel(fout, keyword, funcsig,
12220 					 finfo->dobj.namespace->dobj.name, finfo->rolname,
12221 					 finfo->dobj.catId, 0, finfo->dobj.dumpId);
12222 
12223 	if (finfo->dobj.dump & DUMP_COMPONENT_ACL)
12224 		dumpACL(fout, finfo->dobj.dumpId, InvalidDumpId, keyword,
12225 				funcsig, NULL,
12226 				finfo->dobj.namespace->dobj.name,
12227 				finfo->rolname, finfo->proacl, finfo->rproacl,
12228 				finfo->initproacl, finfo->initrproacl);
12229 
12230 	PQclear(res);
12231 
12232 	destroyPQExpBuffer(query);
12233 	destroyPQExpBuffer(q);
12234 	destroyPQExpBuffer(delqry);
12235 	destroyPQExpBuffer(asPart);
12236 	free(funcsig);
12237 	if (funcfullsig)
12238 		free(funcfullsig);
12239 	free(funcsig_tag);
12240 	if (allargtypes)
12241 		free(allargtypes);
12242 	if (argmodes)
12243 		free(argmodes);
12244 	if (argnames)
12245 		free(argnames);
12246 	if (configitems)
12247 		free(configitems);
12248 }
12249 
12250 
12251 /*
12252  * Dump a user-defined cast
12253  */
12254 static void
dumpCast(Archive * fout,CastInfo * cast)12255 dumpCast(Archive *fout, CastInfo *cast)
12256 {
12257 	DumpOptions *dopt = fout->dopt;
12258 	PQExpBuffer defqry;
12259 	PQExpBuffer delqry;
12260 	PQExpBuffer labelq;
12261 	PQExpBuffer castargs;
12262 	FuncInfo   *funcInfo = NULL;
12263 	const char *sourceType;
12264 	const char *targetType;
12265 
12266 	/* Skip if not to be dumped */
12267 	if (!cast->dobj.dump || dopt->dataOnly)
12268 		return;
12269 
12270 	/* Cannot dump if we don't have the cast function's info */
12271 	if (OidIsValid(cast->castfunc))
12272 	{
12273 		funcInfo = findFuncByOid(cast->castfunc);
12274 		if (funcInfo == NULL)
12275 			exit_horribly(NULL, "could not find function definition for function with OID %u\n",
12276 						  cast->castfunc);
12277 	}
12278 
12279 	defqry = createPQExpBuffer();
12280 	delqry = createPQExpBuffer();
12281 	labelq = createPQExpBuffer();
12282 	castargs = createPQExpBuffer();
12283 
12284 	sourceType = getFormattedTypeName(fout, cast->castsource, zeroAsNone);
12285 	targetType = getFormattedTypeName(fout, cast->casttarget, zeroAsNone);
12286 	appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
12287 					  sourceType, targetType);
12288 
12289 	appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
12290 					  sourceType, targetType);
12291 
12292 	switch (cast->castmethod)
12293 	{
12294 		case COERCION_METHOD_BINARY:
12295 			appendPQExpBufferStr(defqry, "WITHOUT FUNCTION");
12296 			break;
12297 		case COERCION_METHOD_INOUT:
12298 			appendPQExpBufferStr(defqry, "WITH INOUT");
12299 			break;
12300 		case COERCION_METHOD_FUNCTION:
12301 			if (funcInfo)
12302 			{
12303 				char	   *fsig = format_function_signature(fout, funcInfo, true);
12304 
12305 				/*
12306 				 * Always qualify the function name (format_function_signature
12307 				 * won't qualify it).
12308 				 */
12309 				appendPQExpBuffer(defqry, "WITH FUNCTION %s.%s",
12310 								  fmtId(funcInfo->dobj.namespace->dobj.name), fsig);
12311 				free(fsig);
12312 			}
12313 			else
12314 				write_msg(NULL, "WARNING: bogus value in pg_cast.castfunc or pg_cast.castmethod field\n");
12315 			break;
12316 		default:
12317 			write_msg(NULL, "WARNING: bogus value in pg_cast.castmethod field\n");
12318 	}
12319 
12320 	if (cast->castcontext == 'a')
12321 		appendPQExpBufferStr(defqry, " AS ASSIGNMENT");
12322 	else if (cast->castcontext == 'i')
12323 		appendPQExpBufferStr(defqry, " AS IMPLICIT");
12324 	appendPQExpBufferStr(defqry, ";\n");
12325 
12326 	appendPQExpBuffer(labelq, "CAST (%s AS %s)",
12327 					  sourceType, targetType);
12328 
12329 	appendPQExpBuffer(castargs, "(%s AS %s)",
12330 					  sourceType, targetType);
12331 
12332 	if (dopt->binary_upgrade)
12333 		binary_upgrade_extension_member(defqry, &cast->dobj,
12334 										"CAST", castargs->data, NULL);
12335 
12336 	if (cast->dobj.dump & DUMP_COMPONENT_DEFINITION)
12337 		ArchiveEntry(fout, cast->dobj.catId, cast->dobj.dumpId,
12338 					 labelq->data,
12339 					 NULL, NULL, "",
12340 					 false, "CAST", SECTION_PRE_DATA,
12341 					 defqry->data, delqry->data, NULL,
12342 					 NULL, 0,
12343 					 NULL, NULL);
12344 
12345 	/* Dump Cast Comments */
12346 	if (cast->dobj.dump & DUMP_COMPONENT_COMMENT)
12347 		dumpComment(fout, "CAST", castargs->data,
12348 					NULL, "",
12349 					cast->dobj.catId, 0, cast->dobj.dumpId);
12350 
12351 	destroyPQExpBuffer(defqry);
12352 	destroyPQExpBuffer(delqry);
12353 	destroyPQExpBuffer(labelq);
12354 	destroyPQExpBuffer(castargs);
12355 }
12356 
12357 /*
12358  * Dump a transform
12359  */
12360 static void
dumpTransform(Archive * fout,TransformInfo * transform)12361 dumpTransform(Archive *fout, TransformInfo *transform)
12362 {
12363 	DumpOptions *dopt = fout->dopt;
12364 	PQExpBuffer defqry;
12365 	PQExpBuffer delqry;
12366 	PQExpBuffer labelq;
12367 	PQExpBuffer transformargs;
12368 	FuncInfo   *fromsqlFuncInfo = NULL;
12369 	FuncInfo   *tosqlFuncInfo = NULL;
12370 	char	   *lanname;
12371 	const char *transformType;
12372 
12373 	/* Skip if not to be dumped */
12374 	if (!transform->dobj.dump || dopt->dataOnly)
12375 		return;
12376 
12377 	/* Cannot dump if we don't have the transform functions' info */
12378 	if (OidIsValid(transform->trffromsql))
12379 	{
12380 		fromsqlFuncInfo = findFuncByOid(transform->trffromsql);
12381 		if (fromsqlFuncInfo == NULL)
12382 			exit_horribly(NULL, "could not find function definition for function with OID %u\n",
12383 						  transform->trffromsql);
12384 	}
12385 	if (OidIsValid(transform->trftosql))
12386 	{
12387 		tosqlFuncInfo = findFuncByOid(transform->trftosql);
12388 		if (tosqlFuncInfo == NULL)
12389 			exit_horribly(NULL, "could not find function definition for function with OID %u\n",
12390 						  transform->trftosql);
12391 	}
12392 
12393 	defqry = createPQExpBuffer();
12394 	delqry = createPQExpBuffer();
12395 	labelq = createPQExpBuffer();
12396 	transformargs = createPQExpBuffer();
12397 
12398 	lanname = get_language_name(fout, transform->trflang);
12399 	transformType = getFormattedTypeName(fout, transform->trftype, zeroAsNone);
12400 
12401 	appendPQExpBuffer(delqry, "DROP TRANSFORM FOR %s LANGUAGE %s;\n",
12402 					  transformType, lanname);
12403 
12404 	appendPQExpBuffer(defqry, "CREATE TRANSFORM FOR %s LANGUAGE %s (",
12405 					  transformType, lanname);
12406 
12407 	if (!transform->trffromsql && !transform->trftosql)
12408 		write_msg(NULL, "WARNING: bogus transform definition, at least one of trffromsql and trftosql should be nonzero\n");
12409 
12410 	if (transform->trffromsql)
12411 	{
12412 		if (fromsqlFuncInfo)
12413 		{
12414 			char	   *fsig = format_function_signature(fout, fromsqlFuncInfo, true);
12415 
12416 			/*
12417 			 * Always qualify the function name (format_function_signature
12418 			 * won't qualify it).
12419 			 */
12420 			appendPQExpBuffer(defqry, "FROM SQL WITH FUNCTION %s.%s",
12421 							  fmtId(fromsqlFuncInfo->dobj.namespace->dobj.name), fsig);
12422 			free(fsig);
12423 		}
12424 		else
12425 			write_msg(NULL, "WARNING: bogus value in pg_transform.trffromsql field\n");
12426 	}
12427 
12428 	if (transform->trftosql)
12429 	{
12430 		if (transform->trffromsql)
12431 			appendPQExpBuffer(defqry, ", ");
12432 
12433 		if (tosqlFuncInfo)
12434 		{
12435 			char	   *fsig = format_function_signature(fout, tosqlFuncInfo, true);
12436 
12437 			/*
12438 			 * Always qualify the function name (format_function_signature
12439 			 * won't qualify it).
12440 			 */
12441 			appendPQExpBuffer(defqry, "TO SQL WITH FUNCTION %s.%s",
12442 							  fmtId(tosqlFuncInfo->dobj.namespace->dobj.name), fsig);
12443 			free(fsig);
12444 		}
12445 		else
12446 			write_msg(NULL, "WARNING: bogus value in pg_transform.trftosql field\n");
12447 	}
12448 
12449 	appendPQExpBuffer(defqry, ");\n");
12450 
12451 	appendPQExpBuffer(labelq, "TRANSFORM FOR %s LANGUAGE %s",
12452 					  transformType, lanname);
12453 
12454 	appendPQExpBuffer(transformargs, "FOR %s LANGUAGE %s",
12455 					  transformType, lanname);
12456 
12457 	if (dopt->binary_upgrade)
12458 		binary_upgrade_extension_member(defqry, &transform->dobj,
12459 										"TRANSFORM", transformargs->data, NULL);
12460 
12461 	if (transform->dobj.dump & DUMP_COMPONENT_DEFINITION)
12462 		ArchiveEntry(fout, transform->dobj.catId, transform->dobj.dumpId,
12463 					 labelq->data,
12464 					 NULL, NULL, "",
12465 					 false, "TRANSFORM", SECTION_PRE_DATA,
12466 					 defqry->data, delqry->data, NULL,
12467 					 transform->dobj.dependencies, transform->dobj.nDeps,
12468 					 NULL, NULL);
12469 
12470 	/* Dump Transform Comments */
12471 	if (transform->dobj.dump & DUMP_COMPONENT_COMMENT)
12472 		dumpComment(fout, "TRANSFORM", transformargs->data,
12473 					NULL, "",
12474 					transform->dobj.catId, 0, transform->dobj.dumpId);
12475 
12476 	free(lanname);
12477 	destroyPQExpBuffer(defqry);
12478 	destroyPQExpBuffer(delqry);
12479 	destroyPQExpBuffer(labelq);
12480 	destroyPQExpBuffer(transformargs);
12481 }
12482 
12483 
12484 /*
12485  * dumpOpr
12486  *	  write out a single operator definition
12487  */
12488 static void
dumpOpr(Archive * fout,OprInfo * oprinfo)12489 dumpOpr(Archive *fout, OprInfo *oprinfo)
12490 {
12491 	DumpOptions *dopt = fout->dopt;
12492 	PQExpBuffer query;
12493 	PQExpBuffer q;
12494 	PQExpBuffer delq;
12495 	PQExpBuffer oprid;
12496 	PQExpBuffer details;
12497 	PGresult   *res;
12498 	int			i_oprkind;
12499 	int			i_oprcode;
12500 	int			i_oprleft;
12501 	int			i_oprright;
12502 	int			i_oprcom;
12503 	int			i_oprnegate;
12504 	int			i_oprrest;
12505 	int			i_oprjoin;
12506 	int			i_oprcanmerge;
12507 	int			i_oprcanhash;
12508 	char	   *oprkind;
12509 	char	   *oprcode;
12510 	char	   *oprleft;
12511 	char	   *oprright;
12512 	char	   *oprcom;
12513 	char	   *oprnegate;
12514 	char	   *oprrest;
12515 	char	   *oprjoin;
12516 	char	   *oprcanmerge;
12517 	char	   *oprcanhash;
12518 	char	   *oprregproc;
12519 	char	   *oprref;
12520 
12521 	/* Skip if not to be dumped */
12522 	if (!oprinfo->dobj.dump || dopt->dataOnly)
12523 		return;
12524 
12525 	/*
12526 	 * some operators are invalid because they were the result of user
12527 	 * defining operators before commutators exist
12528 	 */
12529 	if (!OidIsValid(oprinfo->oprcode))
12530 		return;
12531 
12532 	query = createPQExpBuffer();
12533 	q = createPQExpBuffer();
12534 	delq = createPQExpBuffer();
12535 	oprid = createPQExpBuffer();
12536 	details = createPQExpBuffer();
12537 
12538 	if (fout->remoteVersion >= 80300)
12539 	{
12540 		appendPQExpBuffer(query, "SELECT oprkind, "
12541 						  "oprcode::pg_catalog.regprocedure, "
12542 						  "oprleft::pg_catalog.regtype, "
12543 						  "oprright::pg_catalog.regtype, "
12544 						  "oprcom, "
12545 						  "oprnegate, "
12546 						  "oprrest::pg_catalog.regprocedure, "
12547 						  "oprjoin::pg_catalog.regprocedure, "
12548 						  "oprcanmerge, oprcanhash "
12549 						  "FROM pg_catalog.pg_operator "
12550 						  "WHERE oid = '%u'::pg_catalog.oid",
12551 						  oprinfo->dobj.catId.oid);
12552 	}
12553 	else
12554 	{
12555 		appendPQExpBuffer(query, "SELECT oprkind, "
12556 						  "oprcode::pg_catalog.regprocedure, "
12557 						  "oprleft::pg_catalog.regtype, "
12558 						  "oprright::pg_catalog.regtype, "
12559 						  "oprcom, "
12560 						  "oprnegate, "
12561 						  "oprrest::pg_catalog.regprocedure, "
12562 						  "oprjoin::pg_catalog.regprocedure, "
12563 						  "(oprlsortop != 0) AS oprcanmerge, "
12564 						  "oprcanhash "
12565 						  "FROM pg_catalog.pg_operator "
12566 						  "WHERE oid = '%u'::pg_catalog.oid",
12567 						  oprinfo->dobj.catId.oid);
12568 	}
12569 
12570 	res = ExecuteSqlQueryForSingleRow(fout, query->data);
12571 
12572 	i_oprkind = PQfnumber(res, "oprkind");
12573 	i_oprcode = PQfnumber(res, "oprcode");
12574 	i_oprleft = PQfnumber(res, "oprleft");
12575 	i_oprright = PQfnumber(res, "oprright");
12576 	i_oprcom = PQfnumber(res, "oprcom");
12577 	i_oprnegate = PQfnumber(res, "oprnegate");
12578 	i_oprrest = PQfnumber(res, "oprrest");
12579 	i_oprjoin = PQfnumber(res, "oprjoin");
12580 	i_oprcanmerge = PQfnumber(res, "oprcanmerge");
12581 	i_oprcanhash = PQfnumber(res, "oprcanhash");
12582 
12583 	oprkind = PQgetvalue(res, 0, i_oprkind);
12584 	oprcode = PQgetvalue(res, 0, i_oprcode);
12585 	oprleft = PQgetvalue(res, 0, i_oprleft);
12586 	oprright = PQgetvalue(res, 0, i_oprright);
12587 	oprcom = PQgetvalue(res, 0, i_oprcom);
12588 	oprnegate = PQgetvalue(res, 0, i_oprnegate);
12589 	oprrest = PQgetvalue(res, 0, i_oprrest);
12590 	oprjoin = PQgetvalue(res, 0, i_oprjoin);
12591 	oprcanmerge = PQgetvalue(res, 0, i_oprcanmerge);
12592 	oprcanhash = PQgetvalue(res, 0, i_oprcanhash);
12593 
12594 	oprregproc = convertRegProcReference(fout, oprcode);
12595 	if (oprregproc)
12596 	{
12597 		appendPQExpBuffer(details, "    FUNCTION = %s", oprregproc);
12598 		free(oprregproc);
12599 	}
12600 
12601 	appendPQExpBuffer(oprid, "%s (",
12602 					  oprinfo->dobj.name);
12603 
12604 	/*
12605 	 * right unary means there's a left arg and left unary means there's a
12606 	 * right arg
12607 	 */
12608 	if (strcmp(oprkind, "r") == 0 ||
12609 		strcmp(oprkind, "b") == 0)
12610 	{
12611 		appendPQExpBuffer(details, ",\n    LEFTARG = %s", oprleft);
12612 		appendPQExpBufferStr(oprid, oprleft);
12613 	}
12614 	else
12615 		appendPQExpBufferStr(oprid, "NONE");
12616 
12617 	if (strcmp(oprkind, "l") == 0 ||
12618 		strcmp(oprkind, "b") == 0)
12619 	{
12620 		appendPQExpBuffer(details, ",\n    RIGHTARG = %s", oprright);
12621 		appendPQExpBuffer(oprid, ", %s)", oprright);
12622 	}
12623 	else
12624 		appendPQExpBufferStr(oprid, ", NONE)");
12625 
12626 	oprref = getFormattedOperatorName(fout, oprcom);
12627 	if (oprref)
12628 	{
12629 		appendPQExpBuffer(details, ",\n    COMMUTATOR = %s", oprref);
12630 		free(oprref);
12631 	}
12632 
12633 	oprref = getFormattedOperatorName(fout, oprnegate);
12634 	if (oprref)
12635 	{
12636 		appendPQExpBuffer(details, ",\n    NEGATOR = %s", oprref);
12637 		free(oprref);
12638 	}
12639 
12640 	if (strcmp(oprcanmerge, "t") == 0)
12641 		appendPQExpBufferStr(details, ",\n    MERGES");
12642 
12643 	if (strcmp(oprcanhash, "t") == 0)
12644 		appendPQExpBufferStr(details, ",\n    HASHES");
12645 
12646 	oprregproc = convertRegProcReference(fout, oprrest);
12647 	if (oprregproc)
12648 	{
12649 		appendPQExpBuffer(details, ",\n    RESTRICT = %s", oprregproc);
12650 		free(oprregproc);
12651 	}
12652 
12653 	oprregproc = convertRegProcReference(fout, oprjoin);
12654 	if (oprregproc)
12655 	{
12656 		appendPQExpBuffer(details, ",\n    JOIN = %s", oprregproc);
12657 		free(oprregproc);
12658 	}
12659 
12660 	appendPQExpBuffer(delq, "DROP OPERATOR %s.%s;\n",
12661 					  fmtId(oprinfo->dobj.namespace->dobj.name),
12662 					  oprid->data);
12663 
12664 	appendPQExpBuffer(q, "CREATE OPERATOR %s.%s (\n%s\n);\n",
12665 					  fmtId(oprinfo->dobj.namespace->dobj.name),
12666 					  oprinfo->dobj.name, details->data);
12667 
12668 	if (dopt->binary_upgrade)
12669 		binary_upgrade_extension_member(q, &oprinfo->dobj,
12670 										"OPERATOR", oprid->data,
12671 										oprinfo->dobj.namespace->dobj.name);
12672 
12673 	if (oprinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12674 		ArchiveEntry(fout, oprinfo->dobj.catId, oprinfo->dobj.dumpId,
12675 					 oprinfo->dobj.name,
12676 					 oprinfo->dobj.namespace->dobj.name,
12677 					 NULL,
12678 					 oprinfo->rolname,
12679 					 false, "OPERATOR", SECTION_PRE_DATA,
12680 					 q->data, delq->data, NULL,
12681 					 NULL, 0,
12682 					 NULL, NULL);
12683 
12684 	/* Dump Operator Comments */
12685 	if (oprinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12686 		dumpComment(fout, "OPERATOR", oprid->data,
12687 					oprinfo->dobj.namespace->dobj.name, oprinfo->rolname,
12688 					oprinfo->dobj.catId, 0, oprinfo->dobj.dumpId);
12689 
12690 	PQclear(res);
12691 
12692 	destroyPQExpBuffer(query);
12693 	destroyPQExpBuffer(q);
12694 	destroyPQExpBuffer(delq);
12695 	destroyPQExpBuffer(oprid);
12696 	destroyPQExpBuffer(details);
12697 }
12698 
12699 /*
12700  * Convert a function reference obtained from pg_operator
12701  *
12702  * Returns allocated string of what to print, or NULL if function references
12703  * is InvalidOid. Returned string is expected to be free'd by the caller.
12704  *
12705  * The input is a REGPROCEDURE display; we have to strip the argument-types
12706  * part.
12707  */
12708 static char *
convertRegProcReference(Archive * fout,const char * proc)12709 convertRegProcReference(Archive *fout, const char *proc)
12710 {
12711 	char	   *name;
12712 	char	   *paren;
12713 	bool		inquote;
12714 
12715 	/* In all cases "-" means a null reference */
12716 	if (strcmp(proc, "-") == 0)
12717 		return NULL;
12718 
12719 	name = pg_strdup(proc);
12720 	/* find non-double-quoted left paren */
12721 	inquote = false;
12722 	for (paren = name; *paren; paren++)
12723 	{
12724 		if (*paren == '(' && !inquote)
12725 		{
12726 			*paren = '\0';
12727 			break;
12728 		}
12729 		if (*paren == '"')
12730 			inquote = !inquote;
12731 	}
12732 	return name;
12733 }
12734 
12735 /*
12736  * getFormattedOperatorName - retrieve the operator name for the
12737  * given operator OID (presented in string form).
12738  *
12739  * Returns an allocated string, or NULL if the given OID is invalid.
12740  * Caller is responsible for free'ing result string.
12741  *
12742  * What we produce has the format "OPERATOR(schema.oprname)".  This is only
12743  * useful in commands where the operator's argument types can be inferred from
12744  * context.  We always schema-qualify the name, though.  The predecessor to
12745  * this code tried to skip the schema qualification if possible, but that led
12746  * to wrong results in corner cases, such as if an operator and its negator
12747  * are in different schemas.
12748  */
12749 static char *
getFormattedOperatorName(Archive * fout,const char * oproid)12750 getFormattedOperatorName(Archive *fout, const char *oproid)
12751 {
12752 	OprInfo    *oprInfo;
12753 
12754 	/* In all cases "0" means a null reference */
12755 	if (strcmp(oproid, "0") == 0)
12756 		return NULL;
12757 
12758 	oprInfo = findOprByOid(atooid(oproid));
12759 	if (oprInfo == NULL)
12760 	{
12761 		write_msg(NULL, "WARNING: could not find operator with OID %s\n",
12762 				  oproid);
12763 		return NULL;
12764 	}
12765 
12766 	return psprintf("OPERATOR(%s.%s)",
12767 					fmtId(oprInfo->dobj.namespace->dobj.name),
12768 					oprInfo->dobj.name);
12769 }
12770 
12771 /*
12772  * Convert a function OID obtained from pg_ts_parser or pg_ts_template
12773  *
12774  * It is sufficient to use REGPROC rather than REGPROCEDURE, since the
12775  * argument lists of these functions are predetermined.  Note that the
12776  * caller should ensure we are in the proper schema, because the results
12777  * are search path dependent!
12778  */
12779 static char *
convertTSFunction(Archive * fout,Oid funcOid)12780 convertTSFunction(Archive *fout, Oid funcOid)
12781 {
12782 	char	   *result;
12783 	char		query[128];
12784 	PGresult   *res;
12785 
12786 	snprintf(query, sizeof(query),
12787 			 "SELECT '%u'::pg_catalog.regproc", funcOid);
12788 	res = ExecuteSqlQueryForSingleRow(fout, query);
12789 
12790 	result = pg_strdup(PQgetvalue(res, 0, 0));
12791 
12792 	PQclear(res);
12793 
12794 	return result;
12795 }
12796 
12797 /*
12798  * dumpAccessMethod
12799  *	  write out a single access method definition
12800  */
12801 static void
dumpAccessMethod(Archive * fout,AccessMethodInfo * aminfo)12802 dumpAccessMethod(Archive *fout, AccessMethodInfo *aminfo)
12803 {
12804 	DumpOptions *dopt = fout->dopt;
12805 	PQExpBuffer q;
12806 	PQExpBuffer delq;
12807 	char	   *qamname;
12808 
12809 	/* Skip if not to be dumped */
12810 	if (!aminfo->dobj.dump || dopt->dataOnly)
12811 		return;
12812 
12813 	q = createPQExpBuffer();
12814 	delq = createPQExpBuffer();
12815 
12816 	qamname = pg_strdup(fmtId(aminfo->dobj.name));
12817 
12818 	appendPQExpBuffer(q, "CREATE ACCESS METHOD %s ", qamname);
12819 
12820 	switch (aminfo->amtype)
12821 	{
12822 		case AMTYPE_INDEX:
12823 			appendPQExpBuffer(q, "TYPE INDEX ");
12824 			break;
12825 		default:
12826 			write_msg(NULL, "WARNING: invalid type \"%c\" of access method \"%s\"\n",
12827 					  aminfo->amtype, qamname);
12828 			destroyPQExpBuffer(q);
12829 			destroyPQExpBuffer(delq);
12830 			free(qamname);
12831 			return;
12832 	}
12833 
12834 	appendPQExpBuffer(q, "HANDLER %s;\n", aminfo->amhandler);
12835 
12836 	appendPQExpBuffer(delq, "DROP ACCESS METHOD %s;\n",
12837 					  qamname);
12838 
12839 	if (dopt->binary_upgrade)
12840 		binary_upgrade_extension_member(q, &aminfo->dobj,
12841 										"ACCESS METHOD", qamname, NULL);
12842 
12843 	if (aminfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
12844 		ArchiveEntry(fout, aminfo->dobj.catId, aminfo->dobj.dumpId,
12845 					 aminfo->dobj.name,
12846 					 NULL,
12847 					 NULL,
12848 					 "",
12849 					 false, "ACCESS METHOD", SECTION_PRE_DATA,
12850 					 q->data, delq->data, NULL,
12851 					 NULL, 0,
12852 					 NULL, NULL);
12853 
12854 	/* Dump Access Method Comments */
12855 	if (aminfo->dobj.dump & DUMP_COMPONENT_COMMENT)
12856 		dumpComment(fout, "ACCESS METHOD", qamname,
12857 					NULL, "",
12858 					aminfo->dobj.catId, 0, aminfo->dobj.dumpId);
12859 
12860 	destroyPQExpBuffer(q);
12861 	destroyPQExpBuffer(delq);
12862 	free(qamname);
12863 }
12864 
12865 /*
12866  * dumpOpclass
12867  *	  write out a single operator class definition
12868  */
12869 static void
dumpOpclass(Archive * fout,OpclassInfo * opcinfo)12870 dumpOpclass(Archive *fout, OpclassInfo *opcinfo)
12871 {
12872 	DumpOptions *dopt = fout->dopt;
12873 	PQExpBuffer query;
12874 	PQExpBuffer q;
12875 	PQExpBuffer delq;
12876 	PQExpBuffer nameusing;
12877 	PGresult   *res;
12878 	int			ntups;
12879 	int			i_opcintype;
12880 	int			i_opckeytype;
12881 	int			i_opcdefault;
12882 	int			i_opcfamily;
12883 	int			i_opcfamilyname;
12884 	int			i_opcfamilynsp;
12885 	int			i_amname;
12886 	int			i_amopstrategy;
12887 	int			i_amopreqcheck;
12888 	int			i_amopopr;
12889 	int			i_sortfamily;
12890 	int			i_sortfamilynsp;
12891 	int			i_amprocnum;
12892 	int			i_amproc;
12893 	int			i_amproclefttype;
12894 	int			i_amprocrighttype;
12895 	char	   *opcintype;
12896 	char	   *opckeytype;
12897 	char	   *opcdefault;
12898 	char	   *opcfamily;
12899 	char	   *opcfamilyname;
12900 	char	   *opcfamilynsp;
12901 	char	   *amname;
12902 	char	   *amopstrategy;
12903 	char	   *amopreqcheck;
12904 	char	   *amopopr;
12905 	char	   *sortfamily;
12906 	char	   *sortfamilynsp;
12907 	char	   *amprocnum;
12908 	char	   *amproc;
12909 	char	   *amproclefttype;
12910 	char	   *amprocrighttype;
12911 	bool		needComma;
12912 	int			i;
12913 
12914 	/* Skip if not to be dumped */
12915 	if (!opcinfo->dobj.dump || dopt->dataOnly)
12916 		return;
12917 
12918 	query = createPQExpBuffer();
12919 	q = createPQExpBuffer();
12920 	delq = createPQExpBuffer();
12921 	nameusing = createPQExpBuffer();
12922 
12923 	/* Get additional fields from the pg_opclass row */
12924 	if (fout->remoteVersion >= 80300)
12925 	{
12926 		appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
12927 						  "opckeytype::pg_catalog.regtype, "
12928 						  "opcdefault, opcfamily, "
12929 						  "opfname AS opcfamilyname, "
12930 						  "nspname AS opcfamilynsp, "
12931 						  "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcmethod) AS amname "
12932 						  "FROM pg_catalog.pg_opclass c "
12933 						  "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = opcfamily "
12934 						  "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
12935 						  "WHERE c.oid = '%u'::pg_catalog.oid",
12936 						  opcinfo->dobj.catId.oid);
12937 	}
12938 	else
12939 	{
12940 		appendPQExpBuffer(query, "SELECT opcintype::pg_catalog.regtype, "
12941 						  "opckeytype::pg_catalog.regtype, "
12942 						  "opcdefault, NULL AS opcfamily, "
12943 						  "NULL AS opcfamilyname, "
12944 						  "NULL AS opcfamilynsp, "
12945 						  "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opcamid) AS amname "
12946 						  "FROM pg_catalog.pg_opclass "
12947 						  "WHERE oid = '%u'::pg_catalog.oid",
12948 						  opcinfo->dobj.catId.oid);
12949 	}
12950 
12951 	res = ExecuteSqlQueryForSingleRow(fout, query->data);
12952 
12953 	i_opcintype = PQfnumber(res, "opcintype");
12954 	i_opckeytype = PQfnumber(res, "opckeytype");
12955 	i_opcdefault = PQfnumber(res, "opcdefault");
12956 	i_opcfamily = PQfnumber(res, "opcfamily");
12957 	i_opcfamilyname = PQfnumber(res, "opcfamilyname");
12958 	i_opcfamilynsp = PQfnumber(res, "opcfamilynsp");
12959 	i_amname = PQfnumber(res, "amname");
12960 
12961 	/* opcintype may still be needed after we PQclear res */
12962 	opcintype = pg_strdup(PQgetvalue(res, 0, i_opcintype));
12963 	opckeytype = PQgetvalue(res, 0, i_opckeytype);
12964 	opcdefault = PQgetvalue(res, 0, i_opcdefault);
12965 	/* opcfamily will still be needed after we PQclear res */
12966 	opcfamily = pg_strdup(PQgetvalue(res, 0, i_opcfamily));
12967 	opcfamilyname = PQgetvalue(res, 0, i_opcfamilyname);
12968 	opcfamilynsp = PQgetvalue(res, 0, i_opcfamilynsp);
12969 	/* amname will still be needed after we PQclear res */
12970 	amname = pg_strdup(PQgetvalue(res, 0, i_amname));
12971 
12972 	appendPQExpBuffer(delq, "DROP OPERATOR CLASS %s",
12973 					  fmtQualifiedDumpable(opcinfo));
12974 	appendPQExpBuffer(delq, " USING %s;\n",
12975 					  fmtId(amname));
12976 
12977 	/* Build the fixed portion of the CREATE command */
12978 	appendPQExpBuffer(q, "CREATE OPERATOR CLASS %s\n    ",
12979 					  fmtQualifiedDumpable(opcinfo));
12980 	if (strcmp(opcdefault, "t") == 0)
12981 		appendPQExpBufferStr(q, "DEFAULT ");
12982 	appendPQExpBuffer(q, "FOR TYPE %s USING %s",
12983 					  opcintype,
12984 					  fmtId(amname));
12985 	if (strlen(opcfamilyname) > 0)
12986 	{
12987 		appendPQExpBufferStr(q, " FAMILY ");
12988 		appendPQExpBuffer(q, "%s.", fmtId(opcfamilynsp));
12989 		appendPQExpBufferStr(q, fmtId(opcfamilyname));
12990 	}
12991 	appendPQExpBufferStr(q, " AS\n    ");
12992 
12993 	needComma = false;
12994 
12995 	if (strcmp(opckeytype, "-") != 0)
12996 	{
12997 		appendPQExpBuffer(q, "STORAGE %s",
12998 						  opckeytype);
12999 		needComma = true;
13000 	}
13001 
13002 	PQclear(res);
13003 
13004 	/*
13005 	 * Now fetch and print the OPERATOR entries (pg_amop rows).
13006 	 *
13007 	 * Print only those opfamily members that are tied to the opclass by
13008 	 * pg_depend entries.
13009 	 *
13010 	 * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
13011 	 * older server's opclass in which it is used.  This is to avoid
13012 	 * hard-to-detect breakage if a newer pg_dump is used to dump from an
13013 	 * older server and then reload into that old version.  This can go away
13014 	 * once 8.3 is so old as to not be of interest to anyone.
13015 	 */
13016 	resetPQExpBuffer(query);
13017 
13018 	if (fout->remoteVersion >= 90100)
13019 	{
13020 		appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
13021 						  "amopopr::pg_catalog.regoperator, "
13022 						  "opfname AS sortfamily, "
13023 						  "nspname AS sortfamilynsp "
13024 						  "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
13025 						  "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
13026 						  "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
13027 						  "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
13028 						  "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
13029 						  "AND refobjid = '%u'::pg_catalog.oid "
13030 						  "AND amopfamily = '%s'::pg_catalog.oid "
13031 						  "ORDER BY amopstrategy",
13032 						  opcinfo->dobj.catId.oid,
13033 						  opcfamily);
13034 	}
13035 	else if (fout->remoteVersion >= 80400)
13036 	{
13037 		appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
13038 						  "amopopr::pg_catalog.regoperator, "
13039 						  "NULL AS sortfamily, "
13040 						  "NULL AS sortfamilynsp "
13041 						  "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
13042 						  "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
13043 						  "AND refobjid = '%u'::pg_catalog.oid "
13044 						  "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
13045 						  "AND objid = ao.oid "
13046 						  "ORDER BY amopstrategy",
13047 						  opcinfo->dobj.catId.oid);
13048 	}
13049 	else if (fout->remoteVersion >= 80300)
13050 	{
13051 		appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
13052 						  "amopopr::pg_catalog.regoperator, "
13053 						  "NULL AS sortfamily, "
13054 						  "NULL AS sortfamilynsp "
13055 						  "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
13056 						  "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
13057 						  "AND refobjid = '%u'::pg_catalog.oid "
13058 						  "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
13059 						  "AND objid = ao.oid "
13060 						  "ORDER BY amopstrategy",
13061 						  opcinfo->dobj.catId.oid);
13062 	}
13063 	else
13064 	{
13065 		/*
13066 		 * Here, we print all entries since there are no opfamilies and hence
13067 		 * no loose operators to worry about.
13068 		 */
13069 		appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
13070 						  "amopopr::pg_catalog.regoperator, "
13071 						  "NULL AS sortfamily, "
13072 						  "NULL AS sortfamilynsp "
13073 						  "FROM pg_catalog.pg_amop "
13074 						  "WHERE amopclaid = '%u'::pg_catalog.oid "
13075 						  "ORDER BY amopstrategy",
13076 						  opcinfo->dobj.catId.oid);
13077 	}
13078 
13079 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13080 
13081 	ntups = PQntuples(res);
13082 
13083 	i_amopstrategy = PQfnumber(res, "amopstrategy");
13084 	i_amopreqcheck = PQfnumber(res, "amopreqcheck");
13085 	i_amopopr = PQfnumber(res, "amopopr");
13086 	i_sortfamily = PQfnumber(res, "sortfamily");
13087 	i_sortfamilynsp = PQfnumber(res, "sortfamilynsp");
13088 
13089 	for (i = 0; i < ntups; i++)
13090 	{
13091 		amopstrategy = PQgetvalue(res, i, i_amopstrategy);
13092 		amopreqcheck = PQgetvalue(res, i, i_amopreqcheck);
13093 		amopopr = PQgetvalue(res, i, i_amopopr);
13094 		sortfamily = PQgetvalue(res, i, i_sortfamily);
13095 		sortfamilynsp = PQgetvalue(res, i, i_sortfamilynsp);
13096 
13097 		if (needComma)
13098 			appendPQExpBufferStr(q, " ,\n    ");
13099 
13100 		appendPQExpBuffer(q, "OPERATOR %s %s",
13101 						  amopstrategy, amopopr);
13102 
13103 		if (strlen(sortfamily) > 0)
13104 		{
13105 			appendPQExpBufferStr(q, " FOR ORDER BY ");
13106 			appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
13107 			appendPQExpBufferStr(q, fmtId(sortfamily));
13108 		}
13109 
13110 		if (strcmp(amopreqcheck, "t") == 0)
13111 			appendPQExpBufferStr(q, " RECHECK");
13112 
13113 		needComma = true;
13114 	}
13115 
13116 	PQclear(res);
13117 
13118 	/*
13119 	 * Now fetch and print the FUNCTION entries (pg_amproc rows).
13120 	 *
13121 	 * Print only those opfamily members that are tied to the opclass by
13122 	 * pg_depend entries.
13123 	 *
13124 	 * We print the amproclefttype/amprocrighttype even though in most cases
13125 	 * the backend could deduce the right values, because of the corner case
13126 	 * of a btree sort support function for a cross-type comparison.  That's
13127 	 * only allowed in 9.2 and later, but for simplicity print them in all
13128 	 * versions that have the columns.
13129 	 */
13130 	resetPQExpBuffer(query);
13131 
13132 	if (fout->remoteVersion >= 80300)
13133 	{
13134 		appendPQExpBuffer(query, "SELECT amprocnum, "
13135 						  "amproc::pg_catalog.regprocedure, "
13136 						  "amproclefttype::pg_catalog.regtype, "
13137 						  "amprocrighttype::pg_catalog.regtype "
13138 						  "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
13139 						  "WHERE refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass "
13140 						  "AND refobjid = '%u'::pg_catalog.oid "
13141 						  "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
13142 						  "AND objid = ap.oid "
13143 						  "ORDER BY amprocnum",
13144 						  opcinfo->dobj.catId.oid);
13145 	}
13146 	else
13147 	{
13148 		appendPQExpBuffer(query, "SELECT amprocnum, "
13149 						  "amproc::pg_catalog.regprocedure, "
13150 						  "'' AS amproclefttype, "
13151 						  "'' AS amprocrighttype "
13152 						  "FROM pg_catalog.pg_amproc "
13153 						  "WHERE amopclaid = '%u'::pg_catalog.oid "
13154 						  "ORDER BY amprocnum",
13155 						  opcinfo->dobj.catId.oid);
13156 	}
13157 
13158 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13159 
13160 	ntups = PQntuples(res);
13161 
13162 	i_amprocnum = PQfnumber(res, "amprocnum");
13163 	i_amproc = PQfnumber(res, "amproc");
13164 	i_amproclefttype = PQfnumber(res, "amproclefttype");
13165 	i_amprocrighttype = PQfnumber(res, "amprocrighttype");
13166 
13167 	for (i = 0; i < ntups; i++)
13168 	{
13169 		amprocnum = PQgetvalue(res, i, i_amprocnum);
13170 		amproc = PQgetvalue(res, i, i_amproc);
13171 		amproclefttype = PQgetvalue(res, i, i_amproclefttype);
13172 		amprocrighttype = PQgetvalue(res, i, i_amprocrighttype);
13173 
13174 		if (needComma)
13175 			appendPQExpBufferStr(q, " ,\n    ");
13176 
13177 		appendPQExpBuffer(q, "FUNCTION %s", amprocnum);
13178 
13179 		if (*amproclefttype && *amprocrighttype)
13180 			appendPQExpBuffer(q, " (%s, %s)", amproclefttype, amprocrighttype);
13181 
13182 		appendPQExpBuffer(q, " %s", amproc);
13183 
13184 		needComma = true;
13185 	}
13186 
13187 	PQclear(res);
13188 
13189 	/*
13190 	 * If needComma is still false it means we haven't added anything after
13191 	 * the AS keyword.  To avoid printing broken SQL, append a dummy STORAGE
13192 	 * clause with the same datatype.  This isn't sanctioned by the
13193 	 * documentation, but actually DefineOpClass will treat it as a no-op.
13194 	 */
13195 	if (!needComma)
13196 		appendPQExpBuffer(q, "STORAGE %s", opcintype);
13197 
13198 	appendPQExpBufferStr(q, ";\n");
13199 
13200 	appendPQExpBufferStr(nameusing, fmtId(opcinfo->dobj.name));
13201 	appendPQExpBuffer(nameusing, " USING %s",
13202 					  fmtId(amname));
13203 
13204 	if (dopt->binary_upgrade)
13205 		binary_upgrade_extension_member(q, &opcinfo->dobj,
13206 										"OPERATOR CLASS", nameusing->data,
13207 										opcinfo->dobj.namespace->dobj.name);
13208 
13209 	if (opcinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13210 		ArchiveEntry(fout, opcinfo->dobj.catId, opcinfo->dobj.dumpId,
13211 					 opcinfo->dobj.name,
13212 					 opcinfo->dobj.namespace->dobj.name,
13213 					 NULL,
13214 					 opcinfo->rolname,
13215 					 false, "OPERATOR CLASS", SECTION_PRE_DATA,
13216 					 q->data, delq->data, NULL,
13217 					 NULL, 0,
13218 					 NULL, NULL);
13219 
13220 	/* Dump Operator Class Comments */
13221 	if (opcinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13222 		dumpComment(fout, "OPERATOR CLASS", nameusing->data,
13223 					opcinfo->dobj.namespace->dobj.name, opcinfo->rolname,
13224 					opcinfo->dobj.catId, 0, opcinfo->dobj.dumpId);
13225 
13226 	free(opcintype);
13227 	free(opcfamily);
13228 	free(amname);
13229 	destroyPQExpBuffer(query);
13230 	destroyPQExpBuffer(q);
13231 	destroyPQExpBuffer(delq);
13232 	destroyPQExpBuffer(nameusing);
13233 }
13234 
13235 /*
13236  * dumpOpfamily
13237  *	  write out a single operator family definition
13238  *
13239  * Note: this also dumps any "loose" operator members that aren't bound to a
13240  * specific opclass within the opfamily.
13241  */
13242 static void
dumpOpfamily(Archive * fout,OpfamilyInfo * opfinfo)13243 dumpOpfamily(Archive *fout, OpfamilyInfo *opfinfo)
13244 {
13245 	DumpOptions *dopt = fout->dopt;
13246 	PQExpBuffer query;
13247 	PQExpBuffer q;
13248 	PQExpBuffer delq;
13249 	PQExpBuffer nameusing;
13250 	PGresult   *res;
13251 	PGresult   *res_ops;
13252 	PGresult   *res_procs;
13253 	int			ntups;
13254 	int			i_amname;
13255 	int			i_amopstrategy;
13256 	int			i_amopreqcheck;
13257 	int			i_amopopr;
13258 	int			i_sortfamily;
13259 	int			i_sortfamilynsp;
13260 	int			i_amprocnum;
13261 	int			i_amproc;
13262 	int			i_amproclefttype;
13263 	int			i_amprocrighttype;
13264 	char	   *amname;
13265 	char	   *amopstrategy;
13266 	char	   *amopreqcheck;
13267 	char	   *amopopr;
13268 	char	   *sortfamily;
13269 	char	   *sortfamilynsp;
13270 	char	   *amprocnum;
13271 	char	   *amproc;
13272 	char	   *amproclefttype;
13273 	char	   *amprocrighttype;
13274 	bool		needComma;
13275 	int			i;
13276 
13277 	/* Skip if not to be dumped */
13278 	if (!opfinfo->dobj.dump || dopt->dataOnly)
13279 		return;
13280 
13281 	query = createPQExpBuffer();
13282 	q = createPQExpBuffer();
13283 	delq = createPQExpBuffer();
13284 	nameusing = createPQExpBuffer();
13285 
13286 	/*
13287 	 * Fetch only those opfamily members that are tied directly to the
13288 	 * opfamily by pg_depend entries.
13289 	 *
13290 	 * XXX RECHECK is gone as of 8.4, but we'll still print it if dumping an
13291 	 * older server's opclass in which it is used.  This is to avoid
13292 	 * hard-to-detect breakage if a newer pg_dump is used to dump from an
13293 	 * older server and then reload into that old version.  This can go away
13294 	 * once 8.3 is so old as to not be of interest to anyone.
13295 	 */
13296 	if (fout->remoteVersion >= 90100)
13297 	{
13298 		appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
13299 						  "amopopr::pg_catalog.regoperator, "
13300 						  "opfname AS sortfamily, "
13301 						  "nspname AS sortfamilynsp "
13302 						  "FROM pg_catalog.pg_amop ao JOIN pg_catalog.pg_depend ON "
13303 						  "(classid = 'pg_catalog.pg_amop'::pg_catalog.regclass AND objid = ao.oid) "
13304 						  "LEFT JOIN pg_catalog.pg_opfamily f ON f.oid = amopsortfamily "
13305 						  "LEFT JOIN pg_catalog.pg_namespace n ON n.oid = opfnamespace "
13306 						  "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13307 						  "AND refobjid = '%u'::pg_catalog.oid "
13308 						  "AND amopfamily = '%u'::pg_catalog.oid "
13309 						  "ORDER BY amopstrategy",
13310 						  opfinfo->dobj.catId.oid,
13311 						  opfinfo->dobj.catId.oid);
13312 	}
13313 	else if (fout->remoteVersion >= 80400)
13314 	{
13315 		appendPQExpBuffer(query, "SELECT amopstrategy, false AS amopreqcheck, "
13316 						  "amopopr::pg_catalog.regoperator, "
13317 						  "NULL AS sortfamily, "
13318 						  "NULL AS sortfamilynsp "
13319 						  "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
13320 						  "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13321 						  "AND refobjid = '%u'::pg_catalog.oid "
13322 						  "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
13323 						  "AND objid = ao.oid "
13324 						  "ORDER BY amopstrategy",
13325 						  opfinfo->dobj.catId.oid);
13326 	}
13327 	else
13328 	{
13329 		appendPQExpBuffer(query, "SELECT amopstrategy, amopreqcheck, "
13330 						  "amopopr::pg_catalog.regoperator, "
13331 						  "NULL AS sortfamily, "
13332 						  "NULL AS sortfamilynsp "
13333 						  "FROM pg_catalog.pg_amop ao, pg_catalog.pg_depend "
13334 						  "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13335 						  "AND refobjid = '%u'::pg_catalog.oid "
13336 						  "AND classid = 'pg_catalog.pg_amop'::pg_catalog.regclass "
13337 						  "AND objid = ao.oid "
13338 						  "ORDER BY amopstrategy",
13339 						  opfinfo->dobj.catId.oid);
13340 	}
13341 
13342 	res_ops = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13343 
13344 	resetPQExpBuffer(query);
13345 
13346 	appendPQExpBuffer(query, "SELECT amprocnum, "
13347 					  "amproc::pg_catalog.regprocedure, "
13348 					  "amproclefttype::pg_catalog.regtype, "
13349 					  "amprocrighttype::pg_catalog.regtype "
13350 					  "FROM pg_catalog.pg_amproc ap, pg_catalog.pg_depend "
13351 					  "WHERE refclassid = 'pg_catalog.pg_opfamily'::pg_catalog.regclass "
13352 					  "AND refobjid = '%u'::pg_catalog.oid "
13353 					  "AND classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass "
13354 					  "AND objid = ap.oid "
13355 					  "ORDER BY amprocnum",
13356 					  opfinfo->dobj.catId.oid);
13357 
13358 	res_procs = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
13359 
13360 	/* Get additional fields from the pg_opfamily row */
13361 	resetPQExpBuffer(query);
13362 
13363 	appendPQExpBuffer(query, "SELECT "
13364 					  "(SELECT amname FROM pg_catalog.pg_am WHERE oid = opfmethod) AS amname "
13365 					  "FROM pg_catalog.pg_opfamily "
13366 					  "WHERE oid = '%u'::pg_catalog.oid",
13367 					  opfinfo->dobj.catId.oid);
13368 
13369 	res = ExecuteSqlQueryForSingleRow(fout, query->data);
13370 
13371 	i_amname = PQfnumber(res, "amname");
13372 
13373 	/* amname will still be needed after we PQclear res */
13374 	amname = pg_strdup(PQgetvalue(res, 0, i_amname));
13375 
13376 	appendPQExpBuffer(delq, "DROP OPERATOR FAMILY %s",
13377 					  fmtQualifiedDumpable(opfinfo));
13378 	appendPQExpBuffer(delq, " USING %s;\n",
13379 					  fmtId(amname));
13380 
13381 	/* Build the fixed portion of the CREATE command */
13382 	appendPQExpBuffer(q, "CREATE OPERATOR FAMILY %s",
13383 					  fmtQualifiedDumpable(opfinfo));
13384 	appendPQExpBuffer(q, " USING %s;\n",
13385 					  fmtId(amname));
13386 
13387 	PQclear(res);
13388 
13389 	/* Do we need an ALTER to add loose members? */
13390 	if (PQntuples(res_ops) > 0 || PQntuples(res_procs) > 0)
13391 	{
13392 		appendPQExpBuffer(q, "ALTER OPERATOR FAMILY %s",
13393 						  fmtQualifiedDumpable(opfinfo));
13394 		appendPQExpBuffer(q, " USING %s ADD\n    ",
13395 						  fmtId(amname));
13396 
13397 		needComma = false;
13398 
13399 		/*
13400 		 * Now fetch and print the OPERATOR entries (pg_amop rows).
13401 		 */
13402 		ntups = PQntuples(res_ops);
13403 
13404 		i_amopstrategy = PQfnumber(res_ops, "amopstrategy");
13405 		i_amopreqcheck = PQfnumber(res_ops, "amopreqcheck");
13406 		i_amopopr = PQfnumber(res_ops, "amopopr");
13407 		i_sortfamily = PQfnumber(res_ops, "sortfamily");
13408 		i_sortfamilynsp = PQfnumber(res_ops, "sortfamilynsp");
13409 
13410 		for (i = 0; i < ntups; i++)
13411 		{
13412 			amopstrategy = PQgetvalue(res_ops, i, i_amopstrategy);
13413 			amopreqcheck = PQgetvalue(res_ops, i, i_amopreqcheck);
13414 			amopopr = PQgetvalue(res_ops, i, i_amopopr);
13415 			sortfamily = PQgetvalue(res_ops, i, i_sortfamily);
13416 			sortfamilynsp = PQgetvalue(res_ops, i, i_sortfamilynsp);
13417 
13418 			if (needComma)
13419 				appendPQExpBufferStr(q, " ,\n    ");
13420 
13421 			appendPQExpBuffer(q, "OPERATOR %s %s",
13422 							  amopstrategy, amopopr);
13423 
13424 			if (strlen(sortfamily) > 0)
13425 			{
13426 				appendPQExpBufferStr(q, " FOR ORDER BY ");
13427 				appendPQExpBuffer(q, "%s.", fmtId(sortfamilynsp));
13428 				appendPQExpBufferStr(q, fmtId(sortfamily));
13429 			}
13430 
13431 			if (strcmp(amopreqcheck, "t") == 0)
13432 				appendPQExpBufferStr(q, " RECHECK");
13433 
13434 			needComma = true;
13435 		}
13436 
13437 		/*
13438 		 * Now fetch and print the FUNCTION entries (pg_amproc rows).
13439 		 */
13440 		ntups = PQntuples(res_procs);
13441 
13442 		i_amprocnum = PQfnumber(res_procs, "amprocnum");
13443 		i_amproc = PQfnumber(res_procs, "amproc");
13444 		i_amproclefttype = PQfnumber(res_procs, "amproclefttype");
13445 		i_amprocrighttype = PQfnumber(res_procs, "amprocrighttype");
13446 
13447 		for (i = 0; i < ntups; i++)
13448 		{
13449 			amprocnum = PQgetvalue(res_procs, i, i_amprocnum);
13450 			amproc = PQgetvalue(res_procs, i, i_amproc);
13451 			amproclefttype = PQgetvalue(res_procs, i, i_amproclefttype);
13452 			amprocrighttype = PQgetvalue(res_procs, i, i_amprocrighttype);
13453 
13454 			if (needComma)
13455 				appendPQExpBufferStr(q, " ,\n    ");
13456 
13457 			appendPQExpBuffer(q, "FUNCTION %s (%s, %s) %s",
13458 							  amprocnum, amproclefttype, amprocrighttype,
13459 							  amproc);
13460 
13461 			needComma = true;
13462 		}
13463 
13464 		appendPQExpBufferStr(q, ";\n");
13465 	}
13466 
13467 	appendPQExpBufferStr(nameusing, fmtId(opfinfo->dobj.name));
13468 	appendPQExpBuffer(nameusing, " USING %s",
13469 					  fmtId(amname));
13470 
13471 	if (dopt->binary_upgrade)
13472 		binary_upgrade_extension_member(q, &opfinfo->dobj,
13473 										"OPERATOR FAMILY", nameusing->data,
13474 										opfinfo->dobj.namespace->dobj.name);
13475 
13476 	if (opfinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13477 		ArchiveEntry(fout, opfinfo->dobj.catId, opfinfo->dobj.dumpId,
13478 					 opfinfo->dobj.name,
13479 					 opfinfo->dobj.namespace->dobj.name,
13480 					 NULL,
13481 					 opfinfo->rolname,
13482 					 false, "OPERATOR FAMILY", SECTION_PRE_DATA,
13483 					 q->data, delq->data, NULL,
13484 					 NULL, 0,
13485 					 NULL, NULL);
13486 
13487 	/* Dump Operator Family Comments */
13488 	if (opfinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13489 		dumpComment(fout, "OPERATOR FAMILY", nameusing->data,
13490 					opfinfo->dobj.namespace->dobj.name, opfinfo->rolname,
13491 					opfinfo->dobj.catId, 0, opfinfo->dobj.dumpId);
13492 
13493 	free(amname);
13494 	PQclear(res_ops);
13495 	PQclear(res_procs);
13496 	destroyPQExpBuffer(query);
13497 	destroyPQExpBuffer(q);
13498 	destroyPQExpBuffer(delq);
13499 	destroyPQExpBuffer(nameusing);
13500 }
13501 
13502 /*
13503  * dumpCollation
13504  *	  write out a single collation definition
13505  */
13506 static void
dumpCollation(Archive * fout,CollInfo * collinfo)13507 dumpCollation(Archive *fout, CollInfo *collinfo)
13508 {
13509 	DumpOptions *dopt = fout->dopt;
13510 	PQExpBuffer query;
13511 	PQExpBuffer q;
13512 	PQExpBuffer delq;
13513 	char	   *qcollname;
13514 	PGresult   *res;
13515 	int			i_collprovider;
13516 	int			i_collcollate;
13517 	int			i_collctype;
13518 	const char *collprovider;
13519 	const char *collcollate;
13520 	const char *collctype;
13521 
13522 	/* Skip if not to be dumped */
13523 	if (!collinfo->dobj.dump || dopt->dataOnly)
13524 		return;
13525 
13526 	query = createPQExpBuffer();
13527 	q = createPQExpBuffer();
13528 	delq = createPQExpBuffer();
13529 
13530 	qcollname = pg_strdup(fmtId(collinfo->dobj.name));
13531 
13532 	/* Get collation-specific details */
13533 	if (fout->remoteVersion >= 100000)
13534 		appendPQExpBuffer(query, "SELECT "
13535 						  "collprovider, "
13536 						  "collcollate, "
13537 						  "collctype, "
13538 						  "collversion "
13539 						  "FROM pg_catalog.pg_collation c "
13540 						  "WHERE c.oid = '%u'::pg_catalog.oid",
13541 						  collinfo->dobj.catId.oid);
13542 	else
13543 		appendPQExpBuffer(query, "SELECT "
13544 						  "'c' AS collprovider, "
13545 						  "collcollate, "
13546 						  "collctype, "
13547 						  "NULL AS collversion "
13548 						  "FROM pg_catalog.pg_collation c "
13549 						  "WHERE c.oid = '%u'::pg_catalog.oid",
13550 						  collinfo->dobj.catId.oid);
13551 
13552 	res = ExecuteSqlQueryForSingleRow(fout, query->data);
13553 
13554 	i_collprovider = PQfnumber(res, "collprovider");
13555 	i_collcollate = PQfnumber(res, "collcollate");
13556 	i_collctype = PQfnumber(res, "collctype");
13557 
13558 	collprovider = PQgetvalue(res, 0, i_collprovider);
13559 	collcollate = PQgetvalue(res, 0, i_collcollate);
13560 	collctype = PQgetvalue(res, 0, i_collctype);
13561 
13562 	appendPQExpBuffer(delq, "DROP COLLATION %s;\n",
13563 					  fmtQualifiedDumpable(collinfo));
13564 
13565 	appendPQExpBuffer(q, "CREATE COLLATION %s (",
13566 					  fmtQualifiedDumpable(collinfo));
13567 
13568 	appendPQExpBufferStr(q, "provider = ");
13569 	if (collprovider[0] == 'c')
13570 		appendPQExpBufferStr(q, "libc");
13571 	else if (collprovider[0] == 'i')
13572 		appendPQExpBufferStr(q, "icu");
13573 	else if (collprovider[0] == 'd')
13574 		/* to allow dumping pg_catalog; not accepted on input */
13575 		appendPQExpBufferStr(q, "default");
13576 	else
13577 		exit_horribly(NULL,
13578 					  "unrecognized collation provider: %s\n",
13579 					  collprovider);
13580 
13581 	if (strcmp(collcollate, collctype) == 0)
13582 	{
13583 		appendPQExpBufferStr(q, ", locale = ");
13584 		appendStringLiteralAH(q, collcollate, fout);
13585 	}
13586 	else
13587 	{
13588 		appendPQExpBufferStr(q, ", lc_collate = ");
13589 		appendStringLiteralAH(q, collcollate, fout);
13590 		appendPQExpBufferStr(q, ", lc_ctype = ");
13591 		appendStringLiteralAH(q, collctype, fout);
13592 	}
13593 
13594 	/*
13595 	 * For binary upgrade, carry over the collation version.  For normal
13596 	 * dump/restore, omit the version, so that it is computed upon restore.
13597 	 */
13598 	if (dopt->binary_upgrade)
13599 	{
13600 		int			i_collversion;
13601 
13602 		i_collversion = PQfnumber(res, "collversion");
13603 		if (!PQgetisnull(res, 0, i_collversion))
13604 		{
13605 			appendPQExpBufferStr(q, ", version = ");
13606 			appendStringLiteralAH(q,
13607 								  PQgetvalue(res, 0, i_collversion),
13608 								  fout);
13609 		}
13610 	}
13611 
13612 	appendPQExpBufferStr(q, ");\n");
13613 
13614 	if (dopt->binary_upgrade)
13615 		binary_upgrade_extension_member(q, &collinfo->dobj,
13616 										"COLLATION", qcollname,
13617 										collinfo->dobj.namespace->dobj.name);
13618 
13619 	if (collinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13620 		ArchiveEntry(fout, collinfo->dobj.catId, collinfo->dobj.dumpId,
13621 					 collinfo->dobj.name,
13622 					 collinfo->dobj.namespace->dobj.name,
13623 					 NULL,
13624 					 collinfo->rolname,
13625 					 false, "COLLATION", SECTION_PRE_DATA,
13626 					 q->data, delq->data, NULL,
13627 					 NULL, 0,
13628 					 NULL, NULL);
13629 
13630 	/* Dump Collation Comments */
13631 	if (collinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13632 		dumpComment(fout, "COLLATION", qcollname,
13633 					collinfo->dobj.namespace->dobj.name, collinfo->rolname,
13634 					collinfo->dobj.catId, 0, collinfo->dobj.dumpId);
13635 
13636 	PQclear(res);
13637 
13638 	destroyPQExpBuffer(query);
13639 	destroyPQExpBuffer(q);
13640 	destroyPQExpBuffer(delq);
13641 	free(qcollname);
13642 }
13643 
13644 /*
13645  * dumpConversion
13646  *	  write out a single conversion definition
13647  */
13648 static void
dumpConversion(Archive * fout,ConvInfo * convinfo)13649 dumpConversion(Archive *fout, ConvInfo *convinfo)
13650 {
13651 	DumpOptions *dopt = fout->dopt;
13652 	PQExpBuffer query;
13653 	PQExpBuffer q;
13654 	PQExpBuffer delq;
13655 	char	   *qconvname;
13656 	PGresult   *res;
13657 	int			i_conforencoding;
13658 	int			i_contoencoding;
13659 	int			i_conproc;
13660 	int			i_condefault;
13661 	const char *conforencoding;
13662 	const char *contoencoding;
13663 	const char *conproc;
13664 	bool		condefault;
13665 
13666 	/* Skip if not to be dumped */
13667 	if (!convinfo->dobj.dump || dopt->dataOnly)
13668 		return;
13669 
13670 	query = createPQExpBuffer();
13671 	q = createPQExpBuffer();
13672 	delq = createPQExpBuffer();
13673 
13674 	qconvname = pg_strdup(fmtId(convinfo->dobj.name));
13675 
13676 	/* Get conversion-specific details */
13677 	appendPQExpBuffer(query, "SELECT "
13678 					  "pg_catalog.pg_encoding_to_char(conforencoding) AS conforencoding, "
13679 					  "pg_catalog.pg_encoding_to_char(contoencoding) AS contoencoding, "
13680 					  "conproc, condefault "
13681 					  "FROM pg_catalog.pg_conversion c "
13682 					  "WHERE c.oid = '%u'::pg_catalog.oid",
13683 					  convinfo->dobj.catId.oid);
13684 
13685 	res = ExecuteSqlQueryForSingleRow(fout, query->data);
13686 
13687 	i_conforencoding = PQfnumber(res, "conforencoding");
13688 	i_contoencoding = PQfnumber(res, "contoencoding");
13689 	i_conproc = PQfnumber(res, "conproc");
13690 	i_condefault = PQfnumber(res, "condefault");
13691 
13692 	conforencoding = PQgetvalue(res, 0, i_conforencoding);
13693 	contoencoding = PQgetvalue(res, 0, i_contoencoding);
13694 	conproc = PQgetvalue(res, 0, i_conproc);
13695 	condefault = (PQgetvalue(res, 0, i_condefault)[0] == 't');
13696 
13697 	appendPQExpBuffer(delq, "DROP CONVERSION %s;\n",
13698 					  fmtQualifiedDumpable(convinfo));
13699 
13700 	appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
13701 					  (condefault) ? "DEFAULT " : "",
13702 					  fmtQualifiedDumpable(convinfo));
13703 	appendStringLiteralAH(q, conforencoding, fout);
13704 	appendPQExpBufferStr(q, " TO ");
13705 	appendStringLiteralAH(q, contoencoding, fout);
13706 	/* regproc output is already sufficiently quoted */
13707 	appendPQExpBuffer(q, " FROM %s;\n", conproc);
13708 
13709 	if (dopt->binary_upgrade)
13710 		binary_upgrade_extension_member(q, &convinfo->dobj,
13711 										"CONVERSION", qconvname,
13712 										convinfo->dobj.namespace->dobj.name);
13713 
13714 	if (convinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
13715 		ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
13716 					 convinfo->dobj.name,
13717 					 convinfo->dobj.namespace->dobj.name,
13718 					 NULL,
13719 					 convinfo->rolname,
13720 					 false, "CONVERSION", SECTION_PRE_DATA,
13721 					 q->data, delq->data, NULL,
13722 					 NULL, 0,
13723 					 NULL, NULL);
13724 
13725 	/* Dump Conversion Comments */
13726 	if (convinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
13727 		dumpComment(fout, "CONVERSION", qconvname,
13728 					convinfo->dobj.namespace->dobj.name, convinfo->rolname,
13729 					convinfo->dobj.catId, 0, convinfo->dobj.dumpId);
13730 
13731 	PQclear(res);
13732 
13733 	destroyPQExpBuffer(query);
13734 	destroyPQExpBuffer(q);
13735 	destroyPQExpBuffer(delq);
13736 	free(qconvname);
13737 }
13738 
13739 /*
13740  * format_aggregate_signature: generate aggregate name and argument list
13741  *
13742  * The argument type names are qualified if needed.  The aggregate name
13743  * is never qualified.
13744  */
13745 static char *
format_aggregate_signature(AggInfo * agginfo,Archive * fout,bool honor_quotes)13746 format_aggregate_signature(AggInfo *agginfo, Archive *fout, bool honor_quotes)
13747 {
13748 	PQExpBufferData buf;
13749 	int			j;
13750 
13751 	initPQExpBuffer(&buf);
13752 	if (honor_quotes)
13753 		appendPQExpBufferStr(&buf, fmtId(agginfo->aggfn.dobj.name));
13754 	else
13755 		appendPQExpBufferStr(&buf, agginfo->aggfn.dobj.name);
13756 
13757 	if (agginfo->aggfn.nargs == 0)
13758 		appendPQExpBuffer(&buf, "(*)");
13759 	else
13760 	{
13761 		appendPQExpBufferChar(&buf, '(');
13762 		for (j = 0; j < agginfo->aggfn.nargs; j++)
13763 			appendPQExpBuffer(&buf, "%s%s",
13764 							  (j > 0) ? ", " : "",
13765 							  getFormattedTypeName(fout,
13766 												   agginfo->aggfn.argtypes[j],
13767 												   zeroAsOpaque));
13768 		appendPQExpBufferChar(&buf, ')');
13769 	}
13770 	return buf.data;
13771 }
13772 
13773 /*
13774  * dumpAgg
13775  *	  write out a single aggregate definition
13776  */
13777 static void
dumpAgg(Archive * fout,AggInfo * agginfo)13778 dumpAgg(Archive *fout, AggInfo *agginfo)
13779 {
13780 	DumpOptions *dopt = fout->dopt;
13781 	PQExpBuffer query;
13782 	PQExpBuffer q;
13783 	PQExpBuffer delq;
13784 	PQExpBuffer details;
13785 	char	   *aggsig;			/* identity signature */
13786 	char	   *aggfullsig = NULL;	/* full signature */
13787 	char	   *aggsig_tag;
13788 	PGresult   *res;
13789 	int			i_aggtransfn;
13790 	int			i_aggfinalfn;
13791 	int			i_aggcombinefn;
13792 	int			i_aggserialfn;
13793 	int			i_aggdeserialfn;
13794 	int			i_aggmtransfn;
13795 	int			i_aggminvtransfn;
13796 	int			i_aggmfinalfn;
13797 	int			i_aggfinalextra;
13798 	int			i_aggmfinalextra;
13799 	int			i_aggfinalmodify;
13800 	int			i_aggmfinalmodify;
13801 	int			i_aggsortop;
13802 	int			i_aggkind;
13803 	int			i_aggtranstype;
13804 	int			i_aggtransspace;
13805 	int			i_aggmtranstype;
13806 	int			i_aggmtransspace;
13807 	int			i_agginitval;
13808 	int			i_aggminitval;
13809 	int			i_convertok;
13810 	int			i_proparallel;
13811 	const char *aggtransfn;
13812 	const char *aggfinalfn;
13813 	const char *aggcombinefn;
13814 	const char *aggserialfn;
13815 	const char *aggdeserialfn;
13816 	const char *aggmtransfn;
13817 	const char *aggminvtransfn;
13818 	const char *aggmfinalfn;
13819 	bool		aggfinalextra;
13820 	bool		aggmfinalextra;
13821 	char		aggfinalmodify;
13822 	char		aggmfinalmodify;
13823 	const char *aggsortop;
13824 	char	   *aggsortconvop;
13825 	char		aggkind;
13826 	const char *aggtranstype;
13827 	const char *aggtransspace;
13828 	const char *aggmtranstype;
13829 	const char *aggmtransspace;
13830 	const char *agginitval;
13831 	const char *aggminitval;
13832 	bool		convertok;
13833 	const char *proparallel;
13834 	char		defaultfinalmodify;
13835 
13836 	/* Skip if not to be dumped */
13837 	if (!agginfo->aggfn.dobj.dump || dopt->dataOnly)
13838 		return;
13839 
13840 	query = createPQExpBuffer();
13841 	q = createPQExpBuffer();
13842 	delq = createPQExpBuffer();
13843 	details = createPQExpBuffer();
13844 
13845 	/* Get aggregate-specific details */
13846 	if (fout->remoteVersion >= 110000)
13847 	{
13848 		appendPQExpBuffer(query, "SELECT aggtransfn, "
13849 						  "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13850 						  "aggcombinefn, aggserialfn, aggdeserialfn, aggmtransfn, "
13851 						  "aggminvtransfn, aggmfinalfn, aggmtranstype::pg_catalog.regtype, "
13852 						  "aggfinalextra, aggmfinalextra, "
13853 						  "aggfinalmodify, aggmfinalmodify, "
13854 						  "aggsortop, "
13855 						  "aggkind, "
13856 						  "aggtransspace, agginitval, "
13857 						  "aggmtransspace, aggminitval, "
13858 						  "true AS convertok, "
13859 						  "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
13860 						  "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs, "
13861 						  "p.proparallel "
13862 						  "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13863 						  "WHERE a.aggfnoid = p.oid "
13864 						  "AND p.oid = '%u'::pg_catalog.oid",
13865 						  agginfo->aggfn.dobj.catId.oid);
13866 	}
13867 	else if (fout->remoteVersion >= 90600)
13868 	{
13869 		appendPQExpBuffer(query, "SELECT aggtransfn, "
13870 						  "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13871 						  "aggcombinefn, aggserialfn, aggdeserialfn, aggmtransfn, "
13872 						  "aggminvtransfn, aggmfinalfn, aggmtranstype::pg_catalog.regtype, "
13873 						  "aggfinalextra, aggmfinalextra, "
13874 						  "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13875 						  "aggsortop, "
13876 						  "aggkind, "
13877 						  "aggtransspace, agginitval, "
13878 						  "aggmtransspace, aggminitval, "
13879 						  "true AS convertok, "
13880 						  "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
13881 						  "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs, "
13882 						  "p.proparallel "
13883 						  "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13884 						  "WHERE a.aggfnoid = p.oid "
13885 						  "AND p.oid = '%u'::pg_catalog.oid",
13886 						  agginfo->aggfn.dobj.catId.oid);
13887 	}
13888 	else if (fout->remoteVersion >= 90400)
13889 	{
13890 		appendPQExpBuffer(query, "SELECT aggtransfn, "
13891 						  "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13892 						  "'-' AS aggcombinefn, '-' AS aggserialfn, "
13893 						  "'-' AS aggdeserialfn, aggmtransfn, aggminvtransfn, "
13894 						  "aggmfinalfn, aggmtranstype::pg_catalog.regtype, "
13895 						  "aggfinalextra, aggmfinalextra, "
13896 						  "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13897 						  "aggsortop, "
13898 						  "aggkind, "
13899 						  "aggtransspace, agginitval, "
13900 						  "aggmtransspace, aggminitval, "
13901 						  "true AS convertok, "
13902 						  "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
13903 						  "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
13904 						  "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13905 						  "WHERE a.aggfnoid = p.oid "
13906 						  "AND p.oid = '%u'::pg_catalog.oid",
13907 						  agginfo->aggfn.dobj.catId.oid);
13908 	}
13909 	else if (fout->remoteVersion >= 80400)
13910 	{
13911 		appendPQExpBuffer(query, "SELECT aggtransfn, "
13912 						  "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13913 						  "'-' AS aggcombinefn, '-' AS aggserialfn, "
13914 						  "'-' AS aggdeserialfn, '-' AS aggmtransfn, "
13915 						  "'-' AS aggminvtransfn, '-' AS aggmfinalfn, "
13916 						  "0 AS aggmtranstype, false AS aggfinalextra, "
13917 						  "false AS aggmfinalextra, "
13918 						  "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13919 						  "aggsortop, "
13920 						  "'n' AS aggkind, "
13921 						  "0 AS aggtransspace, agginitval, "
13922 						  "0 AS aggmtransspace, NULL AS aggminitval, "
13923 						  "true AS convertok, "
13924 						  "pg_catalog.pg_get_function_arguments(p.oid) AS funcargs, "
13925 						  "pg_catalog.pg_get_function_identity_arguments(p.oid) AS funciargs "
13926 						  "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13927 						  "WHERE a.aggfnoid = p.oid "
13928 						  "AND p.oid = '%u'::pg_catalog.oid",
13929 						  agginfo->aggfn.dobj.catId.oid);
13930 	}
13931 	else if (fout->remoteVersion >= 80100)
13932 	{
13933 		appendPQExpBuffer(query, "SELECT aggtransfn, "
13934 						  "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13935 						  "'-' AS aggcombinefn, '-' AS aggserialfn, "
13936 						  "'-' AS aggdeserialfn, '-' AS aggmtransfn, "
13937 						  "'-' AS aggminvtransfn, '-' AS aggmfinalfn, "
13938 						  "0 AS aggmtranstype, false AS aggfinalextra, "
13939 						  "false AS aggmfinalextra, "
13940 						  "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13941 						  "aggsortop, "
13942 						  "'n' AS aggkind, "
13943 						  "0 AS aggtransspace, agginitval, "
13944 						  "0 AS aggmtransspace, NULL AS aggminitval, "
13945 						  "true AS convertok "
13946 						  "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13947 						  "WHERE a.aggfnoid = p.oid "
13948 						  "AND p.oid = '%u'::pg_catalog.oid",
13949 						  agginfo->aggfn.dobj.catId.oid);
13950 	}
13951 	else
13952 	{
13953 		appendPQExpBuffer(query, "SELECT aggtransfn, "
13954 						  "aggfinalfn, aggtranstype::pg_catalog.regtype, "
13955 						  "'-' AS aggcombinefn, '-' AS aggserialfn, "
13956 						  "'-' AS aggdeserialfn, '-' AS aggmtransfn, "
13957 						  "'-' AS aggminvtransfn, '-' AS aggmfinalfn, "
13958 						  "0 AS aggmtranstype, false AS aggfinalextra, "
13959 						  "false AS aggmfinalextra, "
13960 						  "'0' AS aggfinalmodify, '0' AS aggmfinalmodify, "
13961 						  "0 AS aggsortop, "
13962 						  "'n' AS aggkind, "
13963 						  "0 AS aggtransspace, agginitval, "
13964 						  "0 AS aggmtransspace, NULL AS aggminitval, "
13965 						  "true AS convertok "
13966 						  "FROM pg_catalog.pg_aggregate a, pg_catalog.pg_proc p "
13967 						  "WHERE a.aggfnoid = p.oid "
13968 						  "AND p.oid = '%u'::pg_catalog.oid",
13969 						  agginfo->aggfn.dobj.catId.oid);
13970 	}
13971 
13972 	res = ExecuteSqlQueryForSingleRow(fout, query->data);
13973 
13974 	i_aggtransfn = PQfnumber(res, "aggtransfn");
13975 	i_aggfinalfn = PQfnumber(res, "aggfinalfn");
13976 	i_aggcombinefn = PQfnumber(res, "aggcombinefn");
13977 	i_aggserialfn = PQfnumber(res, "aggserialfn");
13978 	i_aggdeserialfn = PQfnumber(res, "aggdeserialfn");
13979 	i_aggmtransfn = PQfnumber(res, "aggmtransfn");
13980 	i_aggminvtransfn = PQfnumber(res, "aggminvtransfn");
13981 	i_aggmfinalfn = PQfnumber(res, "aggmfinalfn");
13982 	i_aggfinalextra = PQfnumber(res, "aggfinalextra");
13983 	i_aggmfinalextra = PQfnumber(res, "aggmfinalextra");
13984 	i_aggfinalmodify = PQfnumber(res, "aggfinalmodify");
13985 	i_aggmfinalmodify = PQfnumber(res, "aggmfinalmodify");
13986 	i_aggsortop = PQfnumber(res, "aggsortop");
13987 	i_aggkind = PQfnumber(res, "aggkind");
13988 	i_aggtranstype = PQfnumber(res, "aggtranstype");
13989 	i_aggtransspace = PQfnumber(res, "aggtransspace");
13990 	i_aggmtranstype = PQfnumber(res, "aggmtranstype");
13991 	i_aggmtransspace = PQfnumber(res, "aggmtransspace");
13992 	i_agginitval = PQfnumber(res, "agginitval");
13993 	i_aggminitval = PQfnumber(res, "aggminitval");
13994 	i_convertok = PQfnumber(res, "convertok");
13995 	i_proparallel = PQfnumber(res, "proparallel");
13996 
13997 	aggtransfn = PQgetvalue(res, 0, i_aggtransfn);
13998 	aggfinalfn = PQgetvalue(res, 0, i_aggfinalfn);
13999 	aggcombinefn = PQgetvalue(res, 0, i_aggcombinefn);
14000 	aggserialfn = PQgetvalue(res, 0, i_aggserialfn);
14001 	aggdeserialfn = PQgetvalue(res, 0, i_aggdeserialfn);
14002 	aggmtransfn = PQgetvalue(res, 0, i_aggmtransfn);
14003 	aggminvtransfn = PQgetvalue(res, 0, i_aggminvtransfn);
14004 	aggmfinalfn = PQgetvalue(res, 0, i_aggmfinalfn);
14005 	aggfinalextra = (PQgetvalue(res, 0, i_aggfinalextra)[0] == 't');
14006 	aggmfinalextra = (PQgetvalue(res, 0, i_aggmfinalextra)[0] == 't');
14007 	aggfinalmodify = PQgetvalue(res, 0, i_aggfinalmodify)[0];
14008 	aggmfinalmodify = PQgetvalue(res, 0, i_aggmfinalmodify)[0];
14009 	aggsortop = PQgetvalue(res, 0, i_aggsortop);
14010 	aggkind = PQgetvalue(res, 0, i_aggkind)[0];
14011 	aggtranstype = PQgetvalue(res, 0, i_aggtranstype);
14012 	aggtransspace = PQgetvalue(res, 0, i_aggtransspace);
14013 	aggmtranstype = PQgetvalue(res, 0, i_aggmtranstype);
14014 	aggmtransspace = PQgetvalue(res, 0, i_aggmtransspace);
14015 	agginitval = PQgetvalue(res, 0, i_agginitval);
14016 	aggminitval = PQgetvalue(res, 0, i_aggminitval);
14017 	convertok = (PQgetvalue(res, 0, i_convertok)[0] == 't');
14018 
14019 	if (fout->remoteVersion >= 80400)
14020 	{
14021 		/* 8.4 or later; we rely on server-side code for most of the work */
14022 		char	   *funcargs;
14023 		char	   *funciargs;
14024 
14025 		funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
14026 		funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
14027 		aggfullsig = format_function_arguments(&agginfo->aggfn, funcargs, true);
14028 		aggsig = format_function_arguments(&agginfo->aggfn, funciargs, true);
14029 	}
14030 	else
14031 		/* pre-8.4, do it ourselves */
14032 		aggsig = format_aggregate_signature(agginfo, fout, true);
14033 
14034 	aggsig_tag = format_aggregate_signature(agginfo, fout, false);
14035 
14036 	if (i_proparallel != -1)
14037 		proparallel = PQgetvalue(res, 0, PQfnumber(res, "proparallel"));
14038 	else
14039 		proparallel = NULL;
14040 
14041 	if (!convertok)
14042 	{
14043 		write_msg(NULL, "WARNING: aggregate function %s could not be dumped correctly for this database version; ignored\n",
14044 				  aggsig);
14045 
14046 		if (aggfullsig)
14047 			free(aggfullsig);
14048 
14049 		free(aggsig);
14050 
14051 		return;
14052 	}
14053 
14054 	/* identify default modify flag for aggkind (must match DefineAggregate) */
14055 	defaultfinalmodify = (aggkind == AGGKIND_NORMAL) ? AGGMODIFY_READ_ONLY : AGGMODIFY_READ_WRITE;
14056 	/* replace omitted flags for old versions */
14057 	if (aggfinalmodify == '0')
14058 		aggfinalmodify = defaultfinalmodify;
14059 	if (aggmfinalmodify == '0')
14060 		aggmfinalmodify = defaultfinalmodify;
14061 
14062 	/* regproc and regtype output is already sufficiently quoted */
14063 	appendPQExpBuffer(details, "    SFUNC = %s,\n    STYPE = %s",
14064 					  aggtransfn, aggtranstype);
14065 
14066 	if (strcmp(aggtransspace, "0") != 0)
14067 	{
14068 		appendPQExpBuffer(details, ",\n    SSPACE = %s",
14069 						  aggtransspace);
14070 	}
14071 
14072 	if (!PQgetisnull(res, 0, i_agginitval))
14073 	{
14074 		appendPQExpBufferStr(details, ",\n    INITCOND = ");
14075 		appendStringLiteralAH(details, agginitval, fout);
14076 	}
14077 
14078 	if (strcmp(aggfinalfn, "-") != 0)
14079 	{
14080 		appendPQExpBuffer(details, ",\n    FINALFUNC = %s",
14081 						  aggfinalfn);
14082 		if (aggfinalextra)
14083 			appendPQExpBufferStr(details, ",\n    FINALFUNC_EXTRA");
14084 		if (aggfinalmodify != defaultfinalmodify)
14085 		{
14086 			switch (aggfinalmodify)
14087 			{
14088 				case AGGMODIFY_READ_ONLY:
14089 					appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = READ_ONLY");
14090 					break;
14091 				case AGGMODIFY_SHAREABLE:
14092 					appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = SHAREABLE");
14093 					break;
14094 				case AGGMODIFY_READ_WRITE:
14095 					appendPQExpBufferStr(details, ",\n    FINALFUNC_MODIFY = READ_WRITE");
14096 					break;
14097 				default:
14098 					exit_horribly(NULL, "unrecognized aggfinalmodify value for aggregate \"%s\"\n",
14099 								  agginfo->aggfn.dobj.name);
14100 					break;
14101 			}
14102 		}
14103 	}
14104 
14105 	if (strcmp(aggcombinefn, "-") != 0)
14106 		appendPQExpBuffer(details, ",\n    COMBINEFUNC = %s", aggcombinefn);
14107 
14108 	if (strcmp(aggserialfn, "-") != 0)
14109 		appendPQExpBuffer(details, ",\n    SERIALFUNC = %s", aggserialfn);
14110 
14111 	if (strcmp(aggdeserialfn, "-") != 0)
14112 		appendPQExpBuffer(details, ",\n    DESERIALFUNC = %s", aggdeserialfn);
14113 
14114 	if (strcmp(aggmtransfn, "-") != 0)
14115 	{
14116 		appendPQExpBuffer(details, ",\n    MSFUNC = %s,\n    MINVFUNC = %s,\n    MSTYPE = %s",
14117 						  aggmtransfn,
14118 						  aggminvtransfn,
14119 						  aggmtranstype);
14120 	}
14121 
14122 	if (strcmp(aggmtransspace, "0") != 0)
14123 	{
14124 		appendPQExpBuffer(details, ",\n    MSSPACE = %s",
14125 						  aggmtransspace);
14126 	}
14127 
14128 	if (!PQgetisnull(res, 0, i_aggminitval))
14129 	{
14130 		appendPQExpBufferStr(details, ",\n    MINITCOND = ");
14131 		appendStringLiteralAH(details, aggminitval, fout);
14132 	}
14133 
14134 	if (strcmp(aggmfinalfn, "-") != 0)
14135 	{
14136 		appendPQExpBuffer(details, ",\n    MFINALFUNC = %s",
14137 						  aggmfinalfn);
14138 		if (aggmfinalextra)
14139 			appendPQExpBufferStr(details, ",\n    MFINALFUNC_EXTRA");
14140 		if (aggmfinalmodify != defaultfinalmodify)
14141 		{
14142 			switch (aggmfinalmodify)
14143 			{
14144 				case AGGMODIFY_READ_ONLY:
14145 					appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = READ_ONLY");
14146 					break;
14147 				case AGGMODIFY_SHAREABLE:
14148 					appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = SHAREABLE");
14149 					break;
14150 				case AGGMODIFY_READ_WRITE:
14151 					appendPQExpBufferStr(details, ",\n    MFINALFUNC_MODIFY = READ_WRITE");
14152 					break;
14153 				default:
14154 					exit_horribly(NULL, "unrecognized aggmfinalmodify value for aggregate \"%s\"\n",
14155 								  agginfo->aggfn.dobj.name);
14156 					break;
14157 			}
14158 		}
14159 	}
14160 
14161 	aggsortconvop = getFormattedOperatorName(fout, aggsortop);
14162 	if (aggsortconvop)
14163 	{
14164 		appendPQExpBuffer(details, ",\n    SORTOP = %s",
14165 						  aggsortconvop);
14166 		free(aggsortconvop);
14167 	}
14168 
14169 	if (aggkind == AGGKIND_HYPOTHETICAL)
14170 		appendPQExpBufferStr(details, ",\n    HYPOTHETICAL");
14171 
14172 	if (proparallel != NULL && proparallel[0] != PROPARALLEL_UNSAFE)
14173 	{
14174 		if (proparallel[0] == PROPARALLEL_SAFE)
14175 			appendPQExpBufferStr(details, ",\n    PARALLEL = safe");
14176 		else if (proparallel[0] == PROPARALLEL_RESTRICTED)
14177 			appendPQExpBufferStr(details, ",\n    PARALLEL = restricted");
14178 		else if (proparallel[0] != PROPARALLEL_UNSAFE)
14179 			exit_horribly(NULL, "unrecognized proparallel value for function \"%s\"\n",
14180 						  agginfo->aggfn.dobj.name);
14181 	}
14182 
14183 	appendPQExpBuffer(delq, "DROP AGGREGATE %s.%s;\n",
14184 					  fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
14185 					  aggsig);
14186 
14187 	appendPQExpBuffer(q, "CREATE AGGREGATE %s.%s (\n%s\n);\n",
14188 					  fmtId(agginfo->aggfn.dobj.namespace->dobj.name),
14189 					  aggfullsig ? aggfullsig : aggsig, details->data);
14190 
14191 	if (dopt->binary_upgrade)
14192 		binary_upgrade_extension_member(q, &agginfo->aggfn.dobj,
14193 										"AGGREGATE", aggsig,
14194 										agginfo->aggfn.dobj.namespace->dobj.name);
14195 
14196 	if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_DEFINITION)
14197 		ArchiveEntry(fout, agginfo->aggfn.dobj.catId,
14198 					 agginfo->aggfn.dobj.dumpId,
14199 					 aggsig_tag,
14200 					 agginfo->aggfn.dobj.namespace->dobj.name,
14201 					 NULL,
14202 					 agginfo->aggfn.rolname,
14203 					 false, "AGGREGATE", SECTION_PRE_DATA,
14204 					 q->data, delq->data, NULL,
14205 					 NULL, 0,
14206 					 NULL, NULL);
14207 
14208 	/* Dump Aggregate Comments */
14209 	if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_COMMENT)
14210 		dumpComment(fout, "AGGREGATE", aggsig,
14211 					agginfo->aggfn.dobj.namespace->dobj.name,
14212 					agginfo->aggfn.rolname,
14213 					agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
14214 
14215 	if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_SECLABEL)
14216 		dumpSecLabel(fout, "AGGREGATE", aggsig,
14217 					 agginfo->aggfn.dobj.namespace->dobj.name,
14218 					 agginfo->aggfn.rolname,
14219 					 agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
14220 
14221 	/*
14222 	 * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
14223 	 * command look like a function's GRANT; in particular this affects the
14224 	 * syntax for zero-argument aggregates and ordered-set aggregates.
14225 	 */
14226 	free(aggsig);
14227 
14228 	aggsig = format_function_signature(fout, &agginfo->aggfn, true);
14229 
14230 	if (agginfo->aggfn.dobj.dump & DUMP_COMPONENT_ACL)
14231 		dumpACL(fout, agginfo->aggfn.dobj.dumpId, InvalidDumpId,
14232 				"FUNCTION", aggsig, NULL,
14233 				agginfo->aggfn.dobj.namespace->dobj.name,
14234 				agginfo->aggfn.rolname, agginfo->aggfn.proacl,
14235 				agginfo->aggfn.rproacl,
14236 				agginfo->aggfn.initproacl, agginfo->aggfn.initrproacl);
14237 
14238 	free(aggsig);
14239 	if (aggfullsig)
14240 		free(aggfullsig);
14241 	free(aggsig_tag);
14242 
14243 	PQclear(res);
14244 
14245 	destroyPQExpBuffer(query);
14246 	destroyPQExpBuffer(q);
14247 	destroyPQExpBuffer(delq);
14248 	destroyPQExpBuffer(details);
14249 }
14250 
14251 /*
14252  * dumpTSParser
14253  *	  write out a single text search parser
14254  */
14255 static void
dumpTSParser(Archive * fout,TSParserInfo * prsinfo)14256 dumpTSParser(Archive *fout, TSParserInfo *prsinfo)
14257 {
14258 	DumpOptions *dopt = fout->dopt;
14259 	PQExpBuffer q;
14260 	PQExpBuffer delq;
14261 	char	   *qprsname;
14262 
14263 	/* Skip if not to be dumped */
14264 	if (!prsinfo->dobj.dump || dopt->dataOnly)
14265 		return;
14266 
14267 	q = createPQExpBuffer();
14268 	delq = createPQExpBuffer();
14269 
14270 	qprsname = pg_strdup(fmtId(prsinfo->dobj.name));
14271 
14272 	appendPQExpBuffer(q, "CREATE TEXT SEARCH PARSER %s (\n",
14273 					  fmtQualifiedDumpable(prsinfo));
14274 
14275 	appendPQExpBuffer(q, "    START = %s,\n",
14276 					  convertTSFunction(fout, prsinfo->prsstart));
14277 	appendPQExpBuffer(q, "    GETTOKEN = %s,\n",
14278 					  convertTSFunction(fout, prsinfo->prstoken));
14279 	appendPQExpBuffer(q, "    END = %s,\n",
14280 					  convertTSFunction(fout, prsinfo->prsend));
14281 	if (prsinfo->prsheadline != InvalidOid)
14282 		appendPQExpBuffer(q, "    HEADLINE = %s,\n",
14283 						  convertTSFunction(fout, prsinfo->prsheadline));
14284 	appendPQExpBuffer(q, "    LEXTYPES = %s );\n",
14285 					  convertTSFunction(fout, prsinfo->prslextype));
14286 
14287 	appendPQExpBuffer(delq, "DROP TEXT SEARCH PARSER %s;\n",
14288 					  fmtQualifiedDumpable(prsinfo));
14289 
14290 	if (dopt->binary_upgrade)
14291 		binary_upgrade_extension_member(q, &prsinfo->dobj,
14292 										"TEXT SEARCH PARSER", qprsname,
14293 										prsinfo->dobj.namespace->dobj.name);
14294 
14295 	if (prsinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14296 		ArchiveEntry(fout, prsinfo->dobj.catId, prsinfo->dobj.dumpId,
14297 					 prsinfo->dobj.name,
14298 					 prsinfo->dobj.namespace->dobj.name,
14299 					 NULL,
14300 					 "",
14301 					 false, "TEXT SEARCH PARSER", SECTION_PRE_DATA,
14302 					 q->data, delq->data, NULL,
14303 					 NULL, 0,
14304 					 NULL, NULL);
14305 
14306 	/* Dump Parser Comments */
14307 	if (prsinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14308 		dumpComment(fout, "TEXT SEARCH PARSER", qprsname,
14309 					prsinfo->dobj.namespace->dobj.name, "",
14310 					prsinfo->dobj.catId, 0, prsinfo->dobj.dumpId);
14311 
14312 	destroyPQExpBuffer(q);
14313 	destroyPQExpBuffer(delq);
14314 	free(qprsname);
14315 }
14316 
14317 /*
14318  * dumpTSDictionary
14319  *	  write out a single text search dictionary
14320  */
14321 static void
dumpTSDictionary(Archive * fout,TSDictInfo * dictinfo)14322 dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo)
14323 {
14324 	DumpOptions *dopt = fout->dopt;
14325 	PQExpBuffer q;
14326 	PQExpBuffer delq;
14327 	PQExpBuffer query;
14328 	char	   *qdictname;
14329 	PGresult   *res;
14330 	char	   *nspname;
14331 	char	   *tmplname;
14332 
14333 	/* Skip if not to be dumped */
14334 	if (!dictinfo->dobj.dump || dopt->dataOnly)
14335 		return;
14336 
14337 	q = createPQExpBuffer();
14338 	delq = createPQExpBuffer();
14339 	query = createPQExpBuffer();
14340 
14341 	qdictname = pg_strdup(fmtId(dictinfo->dobj.name));
14342 
14343 	/* Fetch name and namespace of the dictionary's template */
14344 	appendPQExpBuffer(query, "SELECT nspname, tmplname "
14345 					  "FROM pg_ts_template p, pg_namespace n "
14346 					  "WHERE p.oid = '%u' AND n.oid = tmplnamespace",
14347 					  dictinfo->dicttemplate);
14348 	res = ExecuteSqlQueryForSingleRow(fout, query->data);
14349 	nspname = PQgetvalue(res, 0, 0);
14350 	tmplname = PQgetvalue(res, 0, 1);
14351 
14352 	appendPQExpBuffer(q, "CREATE TEXT SEARCH DICTIONARY %s (\n",
14353 					  fmtQualifiedDumpable(dictinfo));
14354 
14355 	appendPQExpBufferStr(q, "    TEMPLATE = ");
14356 	appendPQExpBuffer(q, "%s.", fmtId(nspname));
14357 	appendPQExpBufferStr(q, fmtId(tmplname));
14358 
14359 	PQclear(res);
14360 
14361 	/* the dictinitoption can be dumped straight into the command */
14362 	if (dictinfo->dictinitoption)
14363 		appendPQExpBuffer(q, ",\n    %s", dictinfo->dictinitoption);
14364 
14365 	appendPQExpBufferStr(q, " );\n");
14366 
14367 	appendPQExpBuffer(delq, "DROP TEXT SEARCH DICTIONARY %s;\n",
14368 					  fmtQualifiedDumpable(dictinfo));
14369 
14370 	if (dopt->binary_upgrade)
14371 		binary_upgrade_extension_member(q, &dictinfo->dobj,
14372 										"TEXT SEARCH DICTIONARY", qdictname,
14373 										dictinfo->dobj.namespace->dobj.name);
14374 
14375 	if (dictinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14376 		ArchiveEntry(fout, dictinfo->dobj.catId, dictinfo->dobj.dumpId,
14377 					 dictinfo->dobj.name,
14378 					 dictinfo->dobj.namespace->dobj.name,
14379 					 NULL,
14380 					 dictinfo->rolname,
14381 					 false, "TEXT SEARCH DICTIONARY", SECTION_PRE_DATA,
14382 					 q->data, delq->data, NULL,
14383 					 NULL, 0,
14384 					 NULL, NULL);
14385 
14386 	/* Dump Dictionary Comments */
14387 	if (dictinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14388 		dumpComment(fout, "TEXT SEARCH DICTIONARY", qdictname,
14389 					dictinfo->dobj.namespace->dobj.name, dictinfo->rolname,
14390 					dictinfo->dobj.catId, 0, dictinfo->dobj.dumpId);
14391 
14392 	destroyPQExpBuffer(q);
14393 	destroyPQExpBuffer(delq);
14394 	destroyPQExpBuffer(query);
14395 	free(qdictname);
14396 }
14397 
14398 /*
14399  * dumpTSTemplate
14400  *	  write out a single text search template
14401  */
14402 static void
dumpTSTemplate(Archive * fout,TSTemplateInfo * tmplinfo)14403 dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo)
14404 {
14405 	DumpOptions *dopt = fout->dopt;
14406 	PQExpBuffer q;
14407 	PQExpBuffer delq;
14408 	char	   *qtmplname;
14409 
14410 	/* Skip if not to be dumped */
14411 	if (!tmplinfo->dobj.dump || dopt->dataOnly)
14412 		return;
14413 
14414 	q = createPQExpBuffer();
14415 	delq = createPQExpBuffer();
14416 
14417 	qtmplname = pg_strdup(fmtId(tmplinfo->dobj.name));
14418 
14419 	appendPQExpBuffer(q, "CREATE TEXT SEARCH TEMPLATE %s (\n",
14420 					  fmtQualifiedDumpable(tmplinfo));
14421 
14422 	if (tmplinfo->tmplinit != InvalidOid)
14423 		appendPQExpBuffer(q, "    INIT = %s,\n",
14424 						  convertTSFunction(fout, tmplinfo->tmplinit));
14425 	appendPQExpBuffer(q, "    LEXIZE = %s );\n",
14426 					  convertTSFunction(fout, tmplinfo->tmpllexize));
14427 
14428 	appendPQExpBuffer(delq, "DROP TEXT SEARCH TEMPLATE %s;\n",
14429 					  fmtQualifiedDumpable(tmplinfo));
14430 
14431 	if (dopt->binary_upgrade)
14432 		binary_upgrade_extension_member(q, &tmplinfo->dobj,
14433 										"TEXT SEARCH TEMPLATE", qtmplname,
14434 										tmplinfo->dobj.namespace->dobj.name);
14435 
14436 	if (tmplinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14437 		ArchiveEntry(fout, tmplinfo->dobj.catId, tmplinfo->dobj.dumpId,
14438 					 tmplinfo->dobj.name,
14439 					 tmplinfo->dobj.namespace->dobj.name,
14440 					 NULL,
14441 					 "",
14442 					 false, "TEXT SEARCH TEMPLATE", SECTION_PRE_DATA,
14443 					 q->data, delq->data, NULL,
14444 					 NULL, 0,
14445 					 NULL, NULL);
14446 
14447 	/* Dump Template Comments */
14448 	if (tmplinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14449 		dumpComment(fout, "TEXT SEARCH TEMPLATE", qtmplname,
14450 					tmplinfo->dobj.namespace->dobj.name, "",
14451 					tmplinfo->dobj.catId, 0, tmplinfo->dobj.dumpId);
14452 
14453 	destroyPQExpBuffer(q);
14454 	destroyPQExpBuffer(delq);
14455 	free(qtmplname);
14456 }
14457 
14458 /*
14459  * dumpTSConfig
14460  *	  write out a single text search configuration
14461  */
14462 static void
dumpTSConfig(Archive * fout,TSConfigInfo * cfginfo)14463 dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo)
14464 {
14465 	DumpOptions *dopt = fout->dopt;
14466 	PQExpBuffer q;
14467 	PQExpBuffer delq;
14468 	PQExpBuffer query;
14469 	char	   *qcfgname;
14470 	PGresult   *res;
14471 	char	   *nspname;
14472 	char	   *prsname;
14473 	int			ntups,
14474 				i;
14475 	int			i_tokenname;
14476 	int			i_dictname;
14477 
14478 	/* Skip if not to be dumped */
14479 	if (!cfginfo->dobj.dump || dopt->dataOnly)
14480 		return;
14481 
14482 	q = createPQExpBuffer();
14483 	delq = createPQExpBuffer();
14484 	query = createPQExpBuffer();
14485 
14486 	qcfgname = pg_strdup(fmtId(cfginfo->dobj.name));
14487 
14488 	/* Fetch name and namespace of the config's parser */
14489 	appendPQExpBuffer(query, "SELECT nspname, prsname "
14490 					  "FROM pg_ts_parser p, pg_namespace n "
14491 					  "WHERE p.oid = '%u' AND n.oid = prsnamespace",
14492 					  cfginfo->cfgparser);
14493 	res = ExecuteSqlQueryForSingleRow(fout, query->data);
14494 	nspname = PQgetvalue(res, 0, 0);
14495 	prsname = PQgetvalue(res, 0, 1);
14496 
14497 	appendPQExpBuffer(q, "CREATE TEXT SEARCH CONFIGURATION %s (\n",
14498 					  fmtQualifiedDumpable(cfginfo));
14499 
14500 	appendPQExpBuffer(q, "    PARSER = %s.", fmtId(nspname));
14501 	appendPQExpBuffer(q, "%s );\n", fmtId(prsname));
14502 
14503 	PQclear(res);
14504 
14505 	resetPQExpBuffer(query);
14506 	appendPQExpBuffer(query,
14507 					  "SELECT\n"
14508 					  "  ( SELECT alias FROM pg_catalog.ts_token_type('%u'::pg_catalog.oid) AS t\n"
14509 					  "    WHERE t.tokid = m.maptokentype ) AS tokenname,\n"
14510 					  "  m.mapdict::pg_catalog.regdictionary AS dictname\n"
14511 					  "FROM pg_catalog.pg_ts_config_map AS m\n"
14512 					  "WHERE m.mapcfg = '%u'\n"
14513 					  "ORDER BY m.mapcfg, m.maptokentype, m.mapseqno",
14514 					  cfginfo->cfgparser, cfginfo->dobj.catId.oid);
14515 
14516 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14517 	ntups = PQntuples(res);
14518 
14519 	i_tokenname = PQfnumber(res, "tokenname");
14520 	i_dictname = PQfnumber(res, "dictname");
14521 
14522 	for (i = 0; i < ntups; i++)
14523 	{
14524 		char	   *tokenname = PQgetvalue(res, i, i_tokenname);
14525 		char	   *dictname = PQgetvalue(res, i, i_dictname);
14526 
14527 		if (i == 0 ||
14528 			strcmp(tokenname, PQgetvalue(res, i - 1, i_tokenname)) != 0)
14529 		{
14530 			/* starting a new token type, so start a new command */
14531 			if (i > 0)
14532 				appendPQExpBufferStr(q, ";\n");
14533 			appendPQExpBuffer(q, "\nALTER TEXT SEARCH CONFIGURATION %s\n",
14534 							  fmtQualifiedDumpable(cfginfo));
14535 			/* tokenname needs quoting, dictname does NOT */
14536 			appendPQExpBuffer(q, "    ADD MAPPING FOR %s WITH %s",
14537 							  fmtId(tokenname), dictname);
14538 		}
14539 		else
14540 			appendPQExpBuffer(q, ", %s", dictname);
14541 	}
14542 
14543 	if (ntups > 0)
14544 		appendPQExpBufferStr(q, ";\n");
14545 
14546 	PQclear(res);
14547 
14548 	appendPQExpBuffer(delq, "DROP TEXT SEARCH CONFIGURATION %s;\n",
14549 					  fmtQualifiedDumpable(cfginfo));
14550 
14551 	if (dopt->binary_upgrade)
14552 		binary_upgrade_extension_member(q, &cfginfo->dobj,
14553 										"TEXT SEARCH CONFIGURATION", qcfgname,
14554 										cfginfo->dobj.namespace->dobj.name);
14555 
14556 	if (cfginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14557 		ArchiveEntry(fout, cfginfo->dobj.catId, cfginfo->dobj.dumpId,
14558 					 cfginfo->dobj.name,
14559 					 cfginfo->dobj.namespace->dobj.name,
14560 					 NULL,
14561 					 cfginfo->rolname,
14562 					 false, "TEXT SEARCH CONFIGURATION", SECTION_PRE_DATA,
14563 					 q->data, delq->data, NULL,
14564 					 NULL, 0,
14565 					 NULL, NULL);
14566 
14567 	/* Dump Configuration Comments */
14568 	if (cfginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14569 		dumpComment(fout, "TEXT SEARCH CONFIGURATION", qcfgname,
14570 					cfginfo->dobj.namespace->dobj.name, cfginfo->rolname,
14571 					cfginfo->dobj.catId, 0, cfginfo->dobj.dumpId);
14572 
14573 	destroyPQExpBuffer(q);
14574 	destroyPQExpBuffer(delq);
14575 	destroyPQExpBuffer(query);
14576 	free(qcfgname);
14577 }
14578 
14579 /*
14580  * dumpForeignDataWrapper
14581  *	  write out a single foreign-data wrapper definition
14582  */
14583 static void
dumpForeignDataWrapper(Archive * fout,FdwInfo * fdwinfo)14584 dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
14585 {
14586 	DumpOptions *dopt = fout->dopt;
14587 	PQExpBuffer q;
14588 	PQExpBuffer delq;
14589 	char	   *qfdwname;
14590 
14591 	/* Skip if not to be dumped */
14592 	if (!fdwinfo->dobj.dump || dopt->dataOnly)
14593 		return;
14594 
14595 	q = createPQExpBuffer();
14596 	delq = createPQExpBuffer();
14597 
14598 	qfdwname = pg_strdup(fmtId(fdwinfo->dobj.name));
14599 
14600 	appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s",
14601 					  qfdwname);
14602 
14603 	if (strcmp(fdwinfo->fdwhandler, "-") != 0)
14604 		appendPQExpBuffer(q, " HANDLER %s", fdwinfo->fdwhandler);
14605 
14606 	if (strcmp(fdwinfo->fdwvalidator, "-") != 0)
14607 		appendPQExpBuffer(q, " VALIDATOR %s", fdwinfo->fdwvalidator);
14608 
14609 	if (strlen(fdwinfo->fdwoptions) > 0)
14610 		appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", fdwinfo->fdwoptions);
14611 
14612 	appendPQExpBufferStr(q, ";\n");
14613 
14614 	appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
14615 					  qfdwname);
14616 
14617 	if (dopt->binary_upgrade)
14618 		binary_upgrade_extension_member(q, &fdwinfo->dobj,
14619 										"FOREIGN DATA WRAPPER", qfdwname,
14620 										NULL);
14621 
14622 	if (fdwinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14623 		ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
14624 					 fdwinfo->dobj.name,
14625 					 NULL,
14626 					 NULL,
14627 					 fdwinfo->rolname,
14628 					 false, "FOREIGN DATA WRAPPER", SECTION_PRE_DATA,
14629 					 q->data, delq->data, NULL,
14630 					 NULL, 0,
14631 					 NULL, NULL);
14632 
14633 	/* Dump Foreign Data Wrapper Comments */
14634 	if (fdwinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14635 		dumpComment(fout, "FOREIGN DATA WRAPPER", qfdwname,
14636 					NULL, fdwinfo->rolname,
14637 					fdwinfo->dobj.catId, 0, fdwinfo->dobj.dumpId);
14638 
14639 	/* Handle the ACL */
14640 	if (fdwinfo->dobj.dump & DUMP_COMPONENT_ACL)
14641 		dumpACL(fout, fdwinfo->dobj.dumpId, InvalidDumpId,
14642 				"FOREIGN DATA WRAPPER", qfdwname, NULL,
14643 				NULL, fdwinfo->rolname,
14644 				fdwinfo->fdwacl, fdwinfo->rfdwacl,
14645 				fdwinfo->initfdwacl, fdwinfo->initrfdwacl);
14646 
14647 	free(qfdwname);
14648 
14649 	destroyPQExpBuffer(q);
14650 	destroyPQExpBuffer(delq);
14651 }
14652 
14653 /*
14654  * dumpForeignServer
14655  *	  write out a foreign server definition
14656  */
14657 static void
dumpForeignServer(Archive * fout,ForeignServerInfo * srvinfo)14658 dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo)
14659 {
14660 	DumpOptions *dopt = fout->dopt;
14661 	PQExpBuffer q;
14662 	PQExpBuffer delq;
14663 	PQExpBuffer query;
14664 	PGresult   *res;
14665 	char	   *qsrvname;
14666 	char	   *fdwname;
14667 
14668 	/* Skip if not to be dumped */
14669 	if (!srvinfo->dobj.dump || dopt->dataOnly)
14670 		return;
14671 
14672 	q = createPQExpBuffer();
14673 	delq = createPQExpBuffer();
14674 	query = createPQExpBuffer();
14675 
14676 	qsrvname = pg_strdup(fmtId(srvinfo->dobj.name));
14677 
14678 	/* look up the foreign-data wrapper */
14679 	appendPQExpBuffer(query, "SELECT fdwname "
14680 					  "FROM pg_foreign_data_wrapper w "
14681 					  "WHERE w.oid = '%u'",
14682 					  srvinfo->srvfdw);
14683 	res = ExecuteSqlQueryForSingleRow(fout, query->data);
14684 	fdwname = PQgetvalue(res, 0, 0);
14685 
14686 	appendPQExpBuffer(q, "CREATE SERVER %s", qsrvname);
14687 	if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
14688 	{
14689 		appendPQExpBufferStr(q, " TYPE ");
14690 		appendStringLiteralAH(q, srvinfo->srvtype, fout);
14691 	}
14692 	if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
14693 	{
14694 		appendPQExpBufferStr(q, " VERSION ");
14695 		appendStringLiteralAH(q, srvinfo->srvversion, fout);
14696 	}
14697 
14698 	appendPQExpBufferStr(q, " FOREIGN DATA WRAPPER ");
14699 	appendPQExpBufferStr(q, fmtId(fdwname));
14700 
14701 	if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
14702 		appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", srvinfo->srvoptions);
14703 
14704 	appendPQExpBufferStr(q, ";\n");
14705 
14706 	appendPQExpBuffer(delq, "DROP SERVER %s;\n",
14707 					  qsrvname);
14708 
14709 	if (dopt->binary_upgrade)
14710 		binary_upgrade_extension_member(q, &srvinfo->dobj,
14711 										"SERVER", qsrvname, NULL);
14712 
14713 	if (srvinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
14714 		ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
14715 					 srvinfo->dobj.name,
14716 					 NULL,
14717 					 NULL,
14718 					 srvinfo->rolname,
14719 					 false, "SERVER", SECTION_PRE_DATA,
14720 					 q->data, delq->data, NULL,
14721 					 NULL, 0,
14722 					 NULL, NULL);
14723 
14724 	/* Dump Foreign Server Comments */
14725 	if (srvinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
14726 		dumpComment(fout, "SERVER", qsrvname,
14727 					NULL, srvinfo->rolname,
14728 					srvinfo->dobj.catId, 0, srvinfo->dobj.dumpId);
14729 
14730 	/* Handle the ACL */
14731 	if (srvinfo->dobj.dump & DUMP_COMPONENT_ACL)
14732 		dumpACL(fout, srvinfo->dobj.dumpId, InvalidDumpId,
14733 				"FOREIGN SERVER", qsrvname, NULL,
14734 				NULL, srvinfo->rolname,
14735 				srvinfo->srvacl, srvinfo->rsrvacl,
14736 				srvinfo->initsrvacl, srvinfo->initrsrvacl);
14737 
14738 	/* Dump user mappings */
14739 	if (srvinfo->dobj.dump & DUMP_COMPONENT_USERMAP)
14740 		dumpUserMappings(fout,
14741 						 srvinfo->dobj.name, NULL,
14742 						 srvinfo->rolname,
14743 						 srvinfo->dobj.catId, srvinfo->dobj.dumpId);
14744 
14745 	free(qsrvname);
14746 
14747 	destroyPQExpBuffer(q);
14748 	destroyPQExpBuffer(delq);
14749 	destroyPQExpBuffer(query);
14750 }
14751 
14752 /*
14753  * dumpUserMappings
14754  *
14755  * This routine is used to dump any user mappings associated with the
14756  * server handed to this routine. Should be called after ArchiveEntry()
14757  * for the server.
14758  */
14759 static void
dumpUserMappings(Archive * fout,const char * servername,const char * namespace,const char * owner,CatalogId catalogId,DumpId dumpId)14760 dumpUserMappings(Archive *fout,
14761 				 const char *servername, const char *namespace,
14762 				 const char *owner,
14763 				 CatalogId catalogId, DumpId dumpId)
14764 {
14765 	PQExpBuffer q;
14766 	PQExpBuffer delq;
14767 	PQExpBuffer query;
14768 	PQExpBuffer tag;
14769 	PGresult   *res;
14770 	int			ntups;
14771 	int			i_usename;
14772 	int			i_umoptions;
14773 	int			i;
14774 
14775 	q = createPQExpBuffer();
14776 	tag = createPQExpBuffer();
14777 	delq = createPQExpBuffer();
14778 	query = createPQExpBuffer();
14779 
14780 	/*
14781 	 * We read from the publicly accessible view pg_user_mappings, so as not
14782 	 * to fail if run by a non-superuser.  Note that the view will show
14783 	 * umoptions as null if the user hasn't got privileges for the associated
14784 	 * server; this means that pg_dump will dump such a mapping, but with no
14785 	 * OPTIONS clause.  A possible alternative is to skip such mappings
14786 	 * altogether, but it's not clear that that's an improvement.
14787 	 */
14788 	appendPQExpBuffer(query,
14789 					  "SELECT usename, "
14790 					  "array_to_string(ARRAY("
14791 					  "SELECT quote_ident(option_name) || ' ' || "
14792 					  "quote_literal(option_value) "
14793 					  "FROM pg_options_to_table(umoptions) "
14794 					  "ORDER BY option_name"
14795 					  "), E',\n    ') AS umoptions "
14796 					  "FROM pg_user_mappings "
14797 					  "WHERE srvid = '%u' "
14798 					  "ORDER BY usename",
14799 					  catalogId.oid);
14800 
14801 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
14802 
14803 	ntups = PQntuples(res);
14804 	i_usename = PQfnumber(res, "usename");
14805 	i_umoptions = PQfnumber(res, "umoptions");
14806 
14807 	for (i = 0; i < ntups; i++)
14808 	{
14809 		char	   *usename;
14810 		char	   *umoptions;
14811 
14812 		usename = PQgetvalue(res, i, i_usename);
14813 		umoptions = PQgetvalue(res, i, i_umoptions);
14814 
14815 		resetPQExpBuffer(q);
14816 		appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(usename));
14817 		appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
14818 
14819 		if (umoptions && strlen(umoptions) > 0)
14820 			appendPQExpBuffer(q, " OPTIONS (\n    %s\n)", umoptions);
14821 
14822 		appendPQExpBufferStr(q, ";\n");
14823 
14824 		resetPQExpBuffer(delq);
14825 		appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s", fmtId(usename));
14826 		appendPQExpBuffer(delq, " SERVER %s;\n", fmtId(servername));
14827 
14828 		resetPQExpBuffer(tag);
14829 		appendPQExpBuffer(tag, "USER MAPPING %s SERVER %s",
14830 						  usename, servername);
14831 
14832 		ArchiveEntry(fout, nilCatalogId, createDumpId(),
14833 					 tag->data,
14834 					 namespace,
14835 					 NULL,
14836 					 owner, false,
14837 					 "USER MAPPING", SECTION_PRE_DATA,
14838 					 q->data, delq->data, NULL,
14839 					 &dumpId, 1,
14840 					 NULL, NULL);
14841 	}
14842 
14843 	PQclear(res);
14844 
14845 	destroyPQExpBuffer(query);
14846 	destroyPQExpBuffer(delq);
14847 	destroyPQExpBuffer(tag);
14848 	destroyPQExpBuffer(q);
14849 }
14850 
14851 /*
14852  * Write out default privileges information
14853  */
14854 static void
dumpDefaultACL(Archive * fout,DefaultACLInfo * daclinfo)14855 dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
14856 {
14857 	DumpOptions *dopt = fout->dopt;
14858 	PQExpBuffer q;
14859 	PQExpBuffer tag;
14860 	const char *type;
14861 
14862 	/* Skip if not to be dumped */
14863 	if (!daclinfo->dobj.dump || dopt->dataOnly || dopt->aclsSkip)
14864 		return;
14865 
14866 	q = createPQExpBuffer();
14867 	tag = createPQExpBuffer();
14868 
14869 	switch (daclinfo->defaclobjtype)
14870 	{
14871 		case DEFACLOBJ_RELATION:
14872 			type = "TABLES";
14873 			break;
14874 		case DEFACLOBJ_SEQUENCE:
14875 			type = "SEQUENCES";
14876 			break;
14877 		case DEFACLOBJ_FUNCTION:
14878 			type = "FUNCTIONS";
14879 			break;
14880 		case DEFACLOBJ_TYPE:
14881 			type = "TYPES";
14882 			break;
14883 		case DEFACLOBJ_NAMESPACE:
14884 			type = "SCHEMAS";
14885 			break;
14886 		default:
14887 			/* shouldn't get here */
14888 			exit_horribly(NULL,
14889 						  "unrecognized object type in default privileges: %d\n",
14890 						  (int) daclinfo->defaclobjtype);
14891 			type = "";			/* keep compiler quiet */
14892 	}
14893 
14894 	appendPQExpBuffer(tag, "DEFAULT PRIVILEGES FOR %s", type);
14895 
14896 	/* build the actual command(s) for this tuple */
14897 	if (!buildDefaultACLCommands(type,
14898 								 daclinfo->dobj.namespace != NULL ?
14899 								 daclinfo->dobj.namespace->dobj.name : NULL,
14900 								 daclinfo->defaclacl,
14901 								 daclinfo->rdefaclacl,
14902 								 daclinfo->initdefaclacl,
14903 								 daclinfo->initrdefaclacl,
14904 								 daclinfo->defaclrole,
14905 								 fout->remoteVersion,
14906 								 q))
14907 		exit_horribly(NULL, "could not parse default ACL list (%s)\n",
14908 					  daclinfo->defaclacl);
14909 
14910 	if (daclinfo->dobj.dump & DUMP_COMPONENT_ACL)
14911 		ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
14912 					 tag->data,
14913 					 daclinfo->dobj.namespace ? daclinfo->dobj.namespace->dobj.name : NULL,
14914 					 NULL,
14915 					 daclinfo->defaclrole,
14916 					 false, "DEFAULT ACL", SECTION_POST_DATA,
14917 					 q->data, "", NULL,
14918 					 NULL, 0,
14919 					 NULL, NULL);
14920 
14921 	destroyPQExpBuffer(tag);
14922 	destroyPQExpBuffer(q);
14923 }
14924 
14925 /*----------
14926  * Write out grant/revoke information
14927  *
14928  * 'objDumpId' is the dump ID of the underlying object.
14929  * 'altDumpId' can be a second dumpId that the ACL entry must also depend on,
14930  *		or InvalidDumpId if there is no need for a second dependency.
14931  * 'type' must be one of
14932  *		TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
14933  *		FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT.
14934  * 'name' is the formatted name of the object.  Must be quoted etc. already.
14935  * 'subname' is the formatted name of the sub-object, if any.  Must be quoted.
14936  *		(Currently we assume that subname is only provided for table columns.)
14937  * 'nspname' is the namespace the object is in (NULL if none).
14938  * 'owner' is the owner, NULL if there is no owner (for languages).
14939  * 'acls' contains the ACL string of the object from the appropriate system
14940  * 		catalog field; it will be passed to buildACLCommands for building the
14941  * 		appropriate GRANT commands.
14942  * 'racls' contains the ACL string of any initial-but-now-revoked ACLs of the
14943  * 		object; it will be passed to buildACLCommands for building the
14944  * 		appropriate REVOKE commands.
14945  * 'initacls' In binary-upgrade mode, ACL string of the object's initial
14946  * 		privileges, to be recorded into pg_init_privs
14947  * 'initracls' In binary-upgrade mode, ACL string of the object's
14948  * 		revoked-from-default privileges, to be recorded into pg_init_privs
14949  *
14950  * NB: initacls/initracls are needed because extensions can set privileges on
14951  * an object during the extension's script file and we record those into
14952  * pg_init_privs as that object's initial privileges.
14953  *
14954  * Returns the dump ID assigned to the ACL TocEntry, or InvalidDumpId if
14955  * no ACL entry was created.
14956  *----------
14957  */
14958 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)14959 dumpACL(Archive *fout, DumpId objDumpId, DumpId altDumpId,
14960 		const char *type, const char *name, const char *subname,
14961 		const char *nspname, const char *owner,
14962 		const char *acls, const char *racls,
14963 		const char *initacls, const char *initracls)
14964 {
14965 	DumpId		aclDumpId = InvalidDumpId;
14966 	DumpOptions *dopt = fout->dopt;
14967 	PQExpBuffer sql;
14968 
14969 	/* Do nothing if ACL dump is not enabled */
14970 	if (dopt->aclsSkip)
14971 		return InvalidDumpId;
14972 
14973 	/* --data-only skips ACLs *except* BLOB ACLs */
14974 	if (dopt->dataOnly && strcmp(type, "LARGE OBJECT") != 0)
14975 		return InvalidDumpId;
14976 
14977 	sql = createPQExpBuffer();
14978 
14979 	/*
14980 	 * Check to see if this object has had any initial ACLs included for it.
14981 	 * If so, we are in binary upgrade mode and these are the ACLs to turn
14982 	 * into GRANT and REVOKE statements to set and record the initial
14983 	 * privileges for an extension object.  Let the backend know that these
14984 	 * are to be recorded by calling binary_upgrade_set_record_init_privs()
14985 	 * before and after.
14986 	 */
14987 	if (strlen(initacls) != 0 || strlen(initracls) != 0)
14988 	{
14989 		appendPQExpBuffer(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\n");
14990 		if (!buildACLCommands(name, subname, nspname, type,
14991 							  initacls, initracls, owner,
14992 							  "", fout->remoteVersion, sql))
14993 			exit_horribly(NULL,
14994 						  "could not parse initial GRANT ACL list (%s) or initial REVOKE ACL list (%s) for object \"%s\" (%s)\n",
14995 						  initacls, initracls, name, type);
14996 		appendPQExpBuffer(sql, "SELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\n");
14997 	}
14998 
14999 	if (!buildACLCommands(name, subname, nspname, type,
15000 						  acls, racls, owner,
15001 						  "", fout->remoteVersion, sql))
15002 		exit_horribly(NULL,
15003 					  "could not parse GRANT ACL list (%s) or REVOKE ACL list (%s) for object \"%s\" (%s)\n",
15004 					  acls, racls, name, type);
15005 
15006 	if (sql->len > 0)
15007 	{
15008 		PQExpBuffer tag = createPQExpBuffer();
15009 		DumpId		aclDeps[2];
15010 		int			nDeps = 0;
15011 
15012 		if (subname)
15013 			appendPQExpBuffer(tag, "COLUMN %s.%s", name, subname);
15014 		else
15015 			appendPQExpBuffer(tag, "%s %s", type, name);
15016 
15017 		aclDeps[nDeps++] = objDumpId;
15018 		if (altDumpId != InvalidDumpId)
15019 			aclDeps[nDeps++] = altDumpId;
15020 
15021 		aclDumpId = createDumpId();
15022 
15023 		ArchiveEntry(fout, nilCatalogId, aclDumpId,
15024 					 tag->data, nspname,
15025 					 NULL,
15026 					 owner ? owner : "",
15027 					 false, "ACL", SECTION_NONE,
15028 					 sql->data, "", NULL,
15029 					 aclDeps, nDeps,
15030 					 NULL, NULL);
15031 
15032 		destroyPQExpBuffer(tag);
15033 	}
15034 
15035 	destroyPQExpBuffer(sql);
15036 
15037 	return aclDumpId;
15038 }
15039 
15040 /*
15041  * dumpSecLabel
15042  *
15043  * This routine is used to dump any security labels associated with the
15044  * object handed to this routine. The routine takes the object type
15045  * and object name (ready to print, except for schema decoration), plus
15046  * the namespace and owner of the object (for labeling the ArchiveEntry),
15047  * plus catalog ID and subid which are the lookup key for pg_seclabel,
15048  * plus the dump ID for the object (for setting a dependency).
15049  * If a matching pg_seclabel entry is found, it is dumped.
15050  *
15051  * Note: although this routine takes a dumpId for dependency purposes,
15052  * that purpose is just to mark the dependency in the emitted dump file
15053  * for possible future use by pg_restore.  We do NOT use it for determining
15054  * ordering of the label in the dump file, because this routine is called
15055  * after dependency sorting occurs.  This routine should be called just after
15056  * calling ArchiveEntry() for the specified object.
15057  */
15058 static void
dumpSecLabel(Archive * fout,const char * type,const char * name,const char * namespace,const char * owner,CatalogId catalogId,int subid,DumpId dumpId)15059 dumpSecLabel(Archive *fout, const char *type, const char *name,
15060 			 const char *namespace, const char *owner,
15061 			 CatalogId catalogId, int subid, DumpId dumpId)
15062 {
15063 	DumpOptions *dopt = fout->dopt;
15064 	SecLabelItem *labels;
15065 	int			nlabels;
15066 	int			i;
15067 	PQExpBuffer query;
15068 
15069 	/* do nothing, if --no-security-labels is supplied */
15070 	if (dopt->no_security_labels)
15071 		return;
15072 
15073 	/* Security labels are schema not data ... except blob labels are data */
15074 	if (strcmp(type, "LARGE OBJECT") != 0)
15075 	{
15076 		if (dopt->dataOnly)
15077 			return;
15078 	}
15079 	else
15080 	{
15081 		/* We do dump blob security labels in binary-upgrade mode */
15082 		if (dopt->schemaOnly && !dopt->binary_upgrade)
15083 			return;
15084 	}
15085 
15086 	/* Search for security labels associated with catalogId, using table */
15087 	nlabels = findSecLabels(fout, catalogId.tableoid, catalogId.oid, &labels);
15088 
15089 	query = createPQExpBuffer();
15090 
15091 	for (i = 0; i < nlabels; i++)
15092 	{
15093 		/*
15094 		 * Ignore label entries for which the subid doesn't match.
15095 		 */
15096 		if (labels[i].objsubid != subid)
15097 			continue;
15098 
15099 		appendPQExpBuffer(query,
15100 						  "SECURITY LABEL FOR %s ON %s ",
15101 						  fmtId(labels[i].provider), type);
15102 		if (namespace && *namespace)
15103 			appendPQExpBuffer(query, "%s.", fmtId(namespace));
15104 		appendPQExpBuffer(query, "%s IS ", name);
15105 		appendStringLiteralAH(query, labels[i].label, fout);
15106 		appendPQExpBufferStr(query, ";\n");
15107 	}
15108 
15109 	if (query->len > 0)
15110 	{
15111 		PQExpBuffer tag = createPQExpBuffer();
15112 
15113 		appendPQExpBuffer(tag, "%s %s", type, name);
15114 		ArchiveEntry(fout, nilCatalogId, createDumpId(),
15115 					 tag->data, namespace, NULL, owner,
15116 					 false, "SECURITY LABEL", SECTION_NONE,
15117 					 query->data, "", NULL,
15118 					 &(dumpId), 1,
15119 					 NULL, NULL);
15120 		destroyPQExpBuffer(tag);
15121 	}
15122 
15123 	destroyPQExpBuffer(query);
15124 }
15125 
15126 /*
15127  * dumpTableSecLabel
15128  *
15129  * As above, but dump security label for both the specified table (or view)
15130  * and its columns.
15131  */
15132 static void
dumpTableSecLabel(Archive * fout,TableInfo * tbinfo,const char * reltypename)15133 dumpTableSecLabel(Archive *fout, TableInfo *tbinfo, const char *reltypename)
15134 {
15135 	DumpOptions *dopt = fout->dopt;
15136 	SecLabelItem *labels;
15137 	int			nlabels;
15138 	int			i;
15139 	PQExpBuffer query;
15140 	PQExpBuffer target;
15141 
15142 	/* do nothing, if --no-security-labels is supplied */
15143 	if (dopt->no_security_labels)
15144 		return;
15145 
15146 	/* SecLabel are SCHEMA not data */
15147 	if (dopt->dataOnly)
15148 		return;
15149 
15150 	/* Search for comments associated with relation, using table */
15151 	nlabels = findSecLabels(fout,
15152 							tbinfo->dobj.catId.tableoid,
15153 							tbinfo->dobj.catId.oid,
15154 							&labels);
15155 
15156 	/* If security labels exist, build SECURITY LABEL statements */
15157 	if (nlabels <= 0)
15158 		return;
15159 
15160 	query = createPQExpBuffer();
15161 	target = createPQExpBuffer();
15162 
15163 	for (i = 0; i < nlabels; i++)
15164 	{
15165 		const char *colname;
15166 		const char *provider = labels[i].provider;
15167 		const char *label = labels[i].label;
15168 		int			objsubid = labels[i].objsubid;
15169 
15170 		resetPQExpBuffer(target);
15171 		if (objsubid == 0)
15172 		{
15173 			appendPQExpBuffer(target, "%s %s", reltypename,
15174 							  fmtQualifiedDumpable(tbinfo));
15175 		}
15176 		else
15177 		{
15178 			colname = getAttrName(objsubid, tbinfo);
15179 			/* first fmtXXX result must be consumed before calling again */
15180 			appendPQExpBuffer(target, "COLUMN %s",
15181 							  fmtQualifiedDumpable(tbinfo));
15182 			appendPQExpBuffer(target, ".%s", fmtId(colname));
15183 		}
15184 		appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
15185 						  fmtId(provider), target->data);
15186 		appendStringLiteralAH(query, label, fout);
15187 		appendPQExpBufferStr(query, ";\n");
15188 	}
15189 	if (query->len > 0)
15190 	{
15191 		resetPQExpBuffer(target);
15192 		appendPQExpBuffer(target, "%s %s", reltypename,
15193 						  fmtId(tbinfo->dobj.name));
15194 		ArchiveEntry(fout, nilCatalogId, createDumpId(),
15195 					 target->data,
15196 					 tbinfo->dobj.namespace->dobj.name,
15197 					 NULL, tbinfo->rolname,
15198 					 false, "SECURITY LABEL", SECTION_NONE,
15199 					 query->data, "", NULL,
15200 					 &(tbinfo->dobj.dumpId), 1,
15201 					 NULL, NULL);
15202 	}
15203 	destroyPQExpBuffer(query);
15204 	destroyPQExpBuffer(target);
15205 }
15206 
15207 /*
15208  * findSecLabels
15209  *
15210  * Find the security label(s), if any, associated with the given object.
15211  * All the objsubid values associated with the given classoid/objoid are
15212  * found with one search.
15213  */
15214 static int
findSecLabels(Archive * fout,Oid classoid,Oid objoid,SecLabelItem ** items)15215 findSecLabels(Archive *fout, Oid classoid, Oid objoid, SecLabelItem **items)
15216 {
15217 	/* static storage for table of security labels */
15218 	static SecLabelItem *labels = NULL;
15219 	static int	nlabels = -1;
15220 
15221 	SecLabelItem *middle = NULL;
15222 	SecLabelItem *low;
15223 	SecLabelItem *high;
15224 	int			nmatch;
15225 
15226 	/* Get security labels if we didn't already */
15227 	if (nlabels < 0)
15228 		nlabels = collectSecLabels(fout, &labels);
15229 
15230 	if (nlabels <= 0)			/* no labels, so no match is possible */
15231 	{
15232 		*items = NULL;
15233 		return 0;
15234 	}
15235 
15236 	/*
15237 	 * Do binary search to find some item matching the object.
15238 	 */
15239 	low = &labels[0];
15240 	high = &labels[nlabels - 1];
15241 	while (low <= high)
15242 	{
15243 		middle = low + (high - low) / 2;
15244 
15245 		if (classoid < middle->classoid)
15246 			high = middle - 1;
15247 		else if (classoid > middle->classoid)
15248 			low = middle + 1;
15249 		else if (objoid < middle->objoid)
15250 			high = middle - 1;
15251 		else if (objoid > middle->objoid)
15252 			low = middle + 1;
15253 		else
15254 			break;				/* found a match */
15255 	}
15256 
15257 	if (low > high)				/* no matches */
15258 	{
15259 		*items = NULL;
15260 		return 0;
15261 	}
15262 
15263 	/*
15264 	 * Now determine how many items match the object.  The search loop
15265 	 * invariant still holds: only items between low and high inclusive could
15266 	 * match.
15267 	 */
15268 	nmatch = 1;
15269 	while (middle > low)
15270 	{
15271 		if (classoid != middle[-1].classoid ||
15272 			objoid != middle[-1].objoid)
15273 			break;
15274 		middle--;
15275 		nmatch++;
15276 	}
15277 
15278 	*items = middle;
15279 
15280 	middle += nmatch;
15281 	while (middle <= high)
15282 	{
15283 		if (classoid != middle->classoid ||
15284 			objoid != middle->objoid)
15285 			break;
15286 		middle++;
15287 		nmatch++;
15288 	}
15289 
15290 	return nmatch;
15291 }
15292 
15293 /*
15294  * collectSecLabels
15295  *
15296  * Construct a table of all security labels available for database objects.
15297  * It's much faster to pull them all at once.
15298  *
15299  * The table is sorted by classoid/objid/objsubid for speed in lookup.
15300  */
15301 static int
collectSecLabels(Archive * fout,SecLabelItem ** items)15302 collectSecLabels(Archive *fout, SecLabelItem **items)
15303 {
15304 	PGresult   *res;
15305 	PQExpBuffer query;
15306 	int			i_label;
15307 	int			i_provider;
15308 	int			i_classoid;
15309 	int			i_objoid;
15310 	int			i_objsubid;
15311 	int			ntups;
15312 	int			i;
15313 	SecLabelItem *labels;
15314 
15315 	query = createPQExpBuffer();
15316 
15317 	appendPQExpBufferStr(query,
15318 						 "SELECT label, provider, classoid, objoid, objsubid "
15319 						 "FROM pg_catalog.pg_seclabel "
15320 						 "ORDER BY classoid, objoid, objsubid");
15321 
15322 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15323 
15324 	/* Construct lookup table containing OIDs in numeric form */
15325 	i_label = PQfnumber(res, "label");
15326 	i_provider = PQfnumber(res, "provider");
15327 	i_classoid = PQfnumber(res, "classoid");
15328 	i_objoid = PQfnumber(res, "objoid");
15329 	i_objsubid = PQfnumber(res, "objsubid");
15330 
15331 	ntups = PQntuples(res);
15332 
15333 	labels = (SecLabelItem *) pg_malloc(ntups * sizeof(SecLabelItem));
15334 
15335 	for (i = 0; i < ntups; i++)
15336 	{
15337 		labels[i].label = PQgetvalue(res, i, i_label);
15338 		labels[i].provider = PQgetvalue(res, i, i_provider);
15339 		labels[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
15340 		labels[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
15341 		labels[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
15342 	}
15343 
15344 	/* Do NOT free the PGresult since we are keeping pointers into it */
15345 	destroyPQExpBuffer(query);
15346 
15347 	*items = labels;
15348 	return ntups;
15349 }
15350 
15351 /*
15352  * dumpTable
15353  *	  write out to fout the declarations (not data) of a user-defined table
15354  */
15355 static void
dumpTable(Archive * fout,TableInfo * tbinfo)15356 dumpTable(Archive *fout, TableInfo *tbinfo)
15357 {
15358 	DumpOptions *dopt = fout->dopt;
15359 	DumpId		tableAclDumpId = InvalidDumpId;
15360 	char	   *namecopy;
15361 
15362 	/*
15363 	 * noop if we are not dumping anything about this table, or if we are
15364 	 * doing a data-only dump
15365 	 */
15366 	if (!tbinfo->dobj.dump || dopt->dataOnly)
15367 		return;
15368 
15369 	if (tbinfo->relkind == RELKIND_SEQUENCE)
15370 		dumpSequence(fout, tbinfo);
15371 	else
15372 		dumpTableSchema(fout, tbinfo);
15373 
15374 	/* Handle the ACL here */
15375 	namecopy = pg_strdup(fmtId(tbinfo->dobj.name));
15376 	if (tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
15377 	{
15378 		const char *objtype =
15379 		(tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" : "TABLE";
15380 
15381 		tableAclDumpId =
15382 			dumpACL(fout, tbinfo->dobj.dumpId, InvalidDumpId,
15383 					objtype, namecopy, NULL,
15384 					tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
15385 					tbinfo->relacl, tbinfo->rrelacl,
15386 					tbinfo->initrelacl, tbinfo->initrrelacl);
15387 	}
15388 
15389 	/*
15390 	 * Handle column ACLs, if any.  Note: we pull these with a separate query
15391 	 * rather than trying to fetch them during getTableAttrs, so that we won't
15392 	 * miss ACLs on system columns.
15393 	 */
15394 	if (fout->remoteVersion >= 80400 && tbinfo->dobj.dump & DUMP_COMPONENT_ACL)
15395 	{
15396 		PQExpBuffer query = createPQExpBuffer();
15397 		PGresult   *res;
15398 		int			i;
15399 
15400 		if (fout->remoteVersion >= 90600)
15401 		{
15402 			PQExpBuffer acl_subquery = createPQExpBuffer();
15403 			PQExpBuffer racl_subquery = createPQExpBuffer();
15404 			PQExpBuffer initacl_subquery = createPQExpBuffer();
15405 			PQExpBuffer initracl_subquery = createPQExpBuffer();
15406 
15407 			buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
15408 							initracl_subquery, "at.attacl", "c.relowner", "'c'",
15409 							dopt->binary_upgrade);
15410 
15411 			appendPQExpBuffer(query,
15412 							  "SELECT at.attname, "
15413 							  "%s AS attacl, "
15414 							  "%s AS rattacl, "
15415 							  "%s AS initattacl, "
15416 							  "%s AS initrattacl "
15417 							  "FROM pg_catalog.pg_attribute at "
15418 							  "JOIN pg_catalog.pg_class c ON (at.attrelid = c.oid) "
15419 							  "LEFT JOIN pg_catalog.pg_init_privs pip ON "
15420 							  "(at.attrelid = pip.objoid "
15421 							  "AND pip.classoid = 'pg_catalog.pg_class'::pg_catalog.regclass "
15422 							  "AND at.attnum = pip.objsubid) "
15423 							  "WHERE at.attrelid = '%u'::pg_catalog.oid AND "
15424 							  "NOT at.attisdropped "
15425 							  "AND ("
15426 							  "%s IS NOT NULL OR "
15427 							  "%s IS NOT NULL OR "
15428 							  "%s IS NOT NULL OR "
15429 							  "%s IS NOT NULL)"
15430 							  "ORDER BY at.attnum",
15431 							  acl_subquery->data,
15432 							  racl_subquery->data,
15433 							  initacl_subquery->data,
15434 							  initracl_subquery->data,
15435 							  tbinfo->dobj.catId.oid,
15436 							  acl_subquery->data,
15437 							  racl_subquery->data,
15438 							  initacl_subquery->data,
15439 							  initracl_subquery->data);
15440 
15441 			destroyPQExpBuffer(acl_subquery);
15442 			destroyPQExpBuffer(racl_subquery);
15443 			destroyPQExpBuffer(initacl_subquery);
15444 			destroyPQExpBuffer(initracl_subquery);
15445 		}
15446 		else
15447 		{
15448 			appendPQExpBuffer(query,
15449 							  "SELECT attname, attacl, NULL as rattacl, "
15450 							  "NULL AS initattacl, NULL AS initrattacl "
15451 							  "FROM pg_catalog.pg_attribute "
15452 							  "WHERE attrelid = '%u'::pg_catalog.oid AND NOT attisdropped "
15453 							  "AND attacl IS NOT NULL "
15454 							  "ORDER BY attnum",
15455 							  tbinfo->dobj.catId.oid);
15456 		}
15457 
15458 		res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15459 
15460 		for (i = 0; i < PQntuples(res); i++)
15461 		{
15462 			char	   *attname = PQgetvalue(res, i, 0);
15463 			char	   *attacl = PQgetvalue(res, i, 1);
15464 			char	   *rattacl = PQgetvalue(res, i, 2);
15465 			char	   *initattacl = PQgetvalue(res, i, 3);
15466 			char	   *initrattacl = PQgetvalue(res, i, 4);
15467 			char	   *attnamecopy;
15468 
15469 			attnamecopy = pg_strdup(fmtId(attname));
15470 
15471 			/*
15472 			 * Column's GRANT type is always TABLE.  Each column ACL depends
15473 			 * on the table-level ACL, since we can restore column ACLs in
15474 			 * parallel but the table-level ACL has to be done first.
15475 			 */
15476 			dumpACL(fout, tbinfo->dobj.dumpId, tableAclDumpId,
15477 					"TABLE", namecopy, attnamecopy,
15478 					tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
15479 					attacl, rattacl, initattacl, initrattacl);
15480 			free(attnamecopy);
15481 		}
15482 		PQclear(res);
15483 		destroyPQExpBuffer(query);
15484 	}
15485 
15486 	free(namecopy);
15487 
15488 	return;
15489 }
15490 
15491 /*
15492  * Create the AS clause for a view or materialized view. The semicolon is
15493  * stripped because a materialized view must add a WITH NO DATA clause.
15494  *
15495  * This returns a new buffer which must be freed by the caller.
15496  */
15497 static PQExpBuffer
createViewAsClause(Archive * fout,TableInfo * tbinfo)15498 createViewAsClause(Archive *fout, TableInfo *tbinfo)
15499 {
15500 	PQExpBuffer query = createPQExpBuffer();
15501 	PQExpBuffer result = createPQExpBuffer();
15502 	PGresult   *res;
15503 	int			len;
15504 
15505 	/* Fetch the view definition */
15506 	appendPQExpBuffer(query,
15507 					  "SELECT pg_catalog.pg_get_viewdef('%u'::pg_catalog.oid) AS viewdef",
15508 					  tbinfo->dobj.catId.oid);
15509 
15510 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
15511 
15512 	if (PQntuples(res) != 1)
15513 	{
15514 		if (PQntuples(res) < 1)
15515 			exit_horribly(NULL, "query to obtain definition of view \"%s\" returned no data\n",
15516 						  tbinfo->dobj.name);
15517 		else
15518 			exit_horribly(NULL, "query to obtain definition of view \"%s\" returned more than one definition\n",
15519 						  tbinfo->dobj.name);
15520 	}
15521 
15522 	len = PQgetlength(res, 0, 0);
15523 
15524 	if (len == 0)
15525 		exit_horribly(NULL, "definition of view \"%s\" appears to be empty (length zero)\n",
15526 					  tbinfo->dobj.name);
15527 
15528 	/* Strip off the trailing semicolon so that other things may follow. */
15529 	Assert(PQgetvalue(res, 0, 0)[len - 1] == ';');
15530 	appendBinaryPQExpBuffer(result, PQgetvalue(res, 0, 0), len - 1);
15531 
15532 	PQclear(res);
15533 	destroyPQExpBuffer(query);
15534 
15535 	return result;
15536 }
15537 
15538 /*
15539  * Create a dummy AS clause for a view.  This is used when the real view
15540  * definition has to be postponed because of circular dependencies.
15541  * We must duplicate the view's external properties -- column names and types
15542  * (including collation) -- so that it works for subsequent references.
15543  *
15544  * This returns a new buffer which must be freed by the caller.
15545  */
15546 static PQExpBuffer
createDummyViewAsClause(Archive * fout,TableInfo * tbinfo)15547 createDummyViewAsClause(Archive *fout, TableInfo *tbinfo)
15548 {
15549 	PQExpBuffer result = createPQExpBuffer();
15550 	int			j;
15551 
15552 	appendPQExpBufferStr(result, "SELECT");
15553 
15554 	for (j = 0; j < tbinfo->numatts; j++)
15555 	{
15556 		if (j > 0)
15557 			appendPQExpBufferChar(result, ',');
15558 		appendPQExpBufferStr(result, "\n    ");
15559 
15560 		appendPQExpBuffer(result, "NULL::%s", tbinfo->atttypnames[j]);
15561 
15562 		/*
15563 		 * Must add collation if not default for the type, because CREATE OR
15564 		 * REPLACE VIEW won't change it
15565 		 */
15566 		if (OidIsValid(tbinfo->attcollation[j]))
15567 		{
15568 			CollInfo   *coll;
15569 
15570 			coll = findCollationByOid(tbinfo->attcollation[j]);
15571 			if (coll)
15572 				appendPQExpBuffer(result, " COLLATE %s",
15573 								  fmtQualifiedDumpable(coll));
15574 		}
15575 
15576 		appendPQExpBuffer(result, " AS %s", fmtId(tbinfo->attnames[j]));
15577 	}
15578 
15579 	return result;
15580 }
15581 
15582 /*
15583  * dumpTableSchema
15584  *	  write the declaration (not data) of one user-defined table or view
15585  */
15586 static void
dumpTableSchema(Archive * fout,TableInfo * tbinfo)15587 dumpTableSchema(Archive *fout, TableInfo *tbinfo)
15588 {
15589 	DumpOptions *dopt = fout->dopt;
15590 	PQExpBuffer q = createPQExpBuffer();
15591 	PQExpBuffer delq = createPQExpBuffer();
15592 	char	   *qrelname;
15593 	char	   *qualrelname;
15594 	int			numParents;
15595 	TableInfo **parents;
15596 	int			actual_atts;	/* number of attrs in this CREATE statement */
15597 	const char *reltypename;
15598 	char	   *storage;
15599 	char	   *srvname;
15600 	char	   *ftoptions;
15601 	int			j,
15602 				k;
15603 
15604 	/* We had better have loaded per-column details about this table */
15605 	Assert(tbinfo->interesting);
15606 
15607 	qrelname = pg_strdup(fmtId(tbinfo->dobj.name));
15608 	qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
15609 
15610 	if (dopt->binary_upgrade)
15611 		binary_upgrade_set_type_oids_by_rel_oid(fout, q,
15612 												tbinfo->dobj.catId.oid);
15613 
15614 	/* Is it a table or a view? */
15615 	if (tbinfo->relkind == RELKIND_VIEW)
15616 	{
15617 		PQExpBuffer result;
15618 
15619 		/*
15620 		 * Note: keep this code in sync with the is_view case in dumpRule()
15621 		 */
15622 
15623 		reltypename = "VIEW";
15624 
15625 		appendPQExpBuffer(delq, "DROP VIEW %s;\n", qualrelname);
15626 
15627 		if (dopt->binary_upgrade)
15628 			binary_upgrade_set_pg_class_oids(fout, q,
15629 											 tbinfo->dobj.catId.oid, false);
15630 
15631 		appendPQExpBuffer(q, "CREATE VIEW %s", qualrelname);
15632 
15633 		if (tbinfo->dummy_view)
15634 			result = createDummyViewAsClause(fout, tbinfo);
15635 		else
15636 		{
15637 			if (nonemptyReloptions(tbinfo->reloptions))
15638 			{
15639 				appendPQExpBufferStr(q, " WITH (");
15640 				appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
15641 				appendPQExpBufferChar(q, ')');
15642 			}
15643 			result = createViewAsClause(fout, tbinfo);
15644 		}
15645 		appendPQExpBuffer(q, " AS\n%s", result->data);
15646 		destroyPQExpBuffer(result);
15647 
15648 		if (tbinfo->checkoption != NULL && !tbinfo->dummy_view)
15649 			appendPQExpBuffer(q, "\n  WITH %s CHECK OPTION", tbinfo->checkoption);
15650 		appendPQExpBufferStr(q, ";\n");
15651 	}
15652 	else
15653 	{
15654 		switch (tbinfo->relkind)
15655 		{
15656 			case RELKIND_FOREIGN_TABLE:
15657 				{
15658 					PQExpBuffer query = createPQExpBuffer();
15659 					PGresult   *res;
15660 					int			i_srvname;
15661 					int			i_ftoptions;
15662 
15663 					reltypename = "FOREIGN TABLE";
15664 
15665 					/* retrieve name of foreign server and generic options */
15666 					appendPQExpBuffer(query,
15667 									  "SELECT fs.srvname, "
15668 									  "pg_catalog.array_to_string(ARRAY("
15669 									  "SELECT pg_catalog.quote_ident(option_name) || "
15670 									  "' ' || pg_catalog.quote_literal(option_value) "
15671 									  "FROM pg_catalog.pg_options_to_table(ftoptions) "
15672 									  "ORDER BY option_name"
15673 									  "), E',\n    ') AS ftoptions "
15674 									  "FROM pg_catalog.pg_foreign_table ft "
15675 									  "JOIN pg_catalog.pg_foreign_server fs "
15676 									  "ON (fs.oid = ft.ftserver) "
15677 									  "WHERE ft.ftrelid = '%u'",
15678 									  tbinfo->dobj.catId.oid);
15679 					res = ExecuteSqlQueryForSingleRow(fout, query->data);
15680 					i_srvname = PQfnumber(res, "srvname");
15681 					i_ftoptions = PQfnumber(res, "ftoptions");
15682 					srvname = pg_strdup(PQgetvalue(res, 0, i_srvname));
15683 					ftoptions = pg_strdup(PQgetvalue(res, 0, i_ftoptions));
15684 					PQclear(res);
15685 					destroyPQExpBuffer(query);
15686 					break;
15687 				}
15688 			case RELKIND_MATVIEW:
15689 				reltypename = "MATERIALIZED VIEW";
15690 				srvname = NULL;
15691 				ftoptions = NULL;
15692 				break;
15693 			default:
15694 				reltypename = "TABLE";
15695 				srvname = NULL;
15696 				ftoptions = NULL;
15697 		}
15698 
15699 		numParents = tbinfo->numParents;
15700 		parents = tbinfo->parents;
15701 
15702 		appendPQExpBuffer(delq, "DROP %s %s;\n", reltypename, qualrelname);
15703 
15704 		if (dopt->binary_upgrade)
15705 			binary_upgrade_set_pg_class_oids(fout, q,
15706 											 tbinfo->dobj.catId.oid, false);
15707 
15708 		appendPQExpBuffer(q, "CREATE %s%s %s",
15709 						  tbinfo->relpersistence == RELPERSISTENCE_UNLOGGED ?
15710 						  "UNLOGGED " : "",
15711 						  reltypename,
15712 						  qualrelname);
15713 
15714 		/*
15715 		 * Attach to type, if reloftype; except in case of a binary upgrade,
15716 		 * we dump the table normally and attach it to the type afterward.
15717 		 */
15718 		if (tbinfo->reloftype && !dopt->binary_upgrade)
15719 			appendPQExpBuffer(q, " OF %s", tbinfo->reloftype);
15720 
15721 		if (tbinfo->relkind != RELKIND_MATVIEW)
15722 		{
15723 			/* Dump the attributes */
15724 			actual_atts = 0;
15725 			for (j = 0; j < tbinfo->numatts; j++)
15726 			{
15727 				/*
15728 				 * Normally, dump if it's locally defined in this table, and
15729 				 * not dropped.  But for binary upgrade, we'll dump all the
15730 				 * columns, and then fix up the dropped and nonlocal cases
15731 				 * below.
15732 				 */
15733 				if (shouldPrintColumn(dopt, tbinfo, j))
15734 				{
15735 					bool		print_default;
15736 					bool		print_notnull;
15737 
15738 					/*
15739 					 * Default value --- suppress if to be printed separately.
15740 					 */
15741 					print_default = (tbinfo->attrdefs[j] != NULL &&
15742 									 !tbinfo->attrdefs[j]->separate);
15743 
15744 					/*
15745 					 * Not Null constraint --- suppress if inherited, except
15746 					 * if partition, or in binary-upgrade case where that
15747 					 * won't work.
15748 					 */
15749 					print_notnull = (tbinfo->notnull[j] &&
15750 									 (!tbinfo->inhNotNull[j] ||
15751 									  tbinfo->ispartition || dopt->binary_upgrade));
15752 
15753 					/*
15754 					 * Skip column if fully defined by reloftype, except in
15755 					 * binary upgrade
15756 					 */
15757 					if (tbinfo->reloftype && !print_default && !print_notnull &&
15758 						!dopt->binary_upgrade)
15759 						continue;
15760 
15761 					/* Format properly if not first attr */
15762 					if (actual_atts == 0)
15763 						appendPQExpBufferStr(q, " (");
15764 					else
15765 						appendPQExpBufferChar(q, ',');
15766 					appendPQExpBufferStr(q, "\n    ");
15767 					actual_atts++;
15768 
15769 					/* Attribute name */
15770 					appendPQExpBufferStr(q, fmtId(tbinfo->attnames[j]));
15771 
15772 					if (tbinfo->attisdropped[j])
15773 					{
15774 						/*
15775 						 * ALTER TABLE DROP COLUMN clears
15776 						 * pg_attribute.atttypid, so we will not have gotten a
15777 						 * valid type name; insert INTEGER as a stopgap. We'll
15778 						 * clean things up later.
15779 						 */
15780 						appendPQExpBufferStr(q, " INTEGER /* dummy */");
15781 						/* and skip to the next column */
15782 						continue;
15783 					}
15784 
15785 					/*
15786 					 * Attribute type; print it except when creating a typed
15787 					 * table ('OF type_name'), but in binary-upgrade mode,
15788 					 * print it in that case too.
15789 					 */
15790 					if (dopt->binary_upgrade || !tbinfo->reloftype)
15791 					{
15792 						appendPQExpBuffer(q, " %s",
15793 										  tbinfo->atttypnames[j]);
15794 					}
15795 
15796 					/* Add collation if not default for the type */
15797 					if (OidIsValid(tbinfo->attcollation[j]))
15798 					{
15799 						CollInfo   *coll;
15800 
15801 						coll = findCollationByOid(tbinfo->attcollation[j]);
15802 						if (coll)
15803 							appendPQExpBuffer(q, " COLLATE %s",
15804 											  fmtQualifiedDumpable(coll));
15805 					}
15806 
15807 					if (print_default)
15808 						appendPQExpBuffer(q, " DEFAULT %s",
15809 										  tbinfo->attrdefs[j]->adef_expr);
15810 
15811 					if (print_notnull)
15812 						appendPQExpBufferStr(q, " NOT NULL");
15813 				}
15814 			}
15815 
15816 			/*
15817 			 * Add non-inherited CHECK constraints, if any.
15818 			 *
15819 			 * For partitions, we need to include check constraints even if
15820 			 * they're not defined locally, because the ALTER TABLE ATTACH
15821 			 * PARTITION that we'll emit later expects the constraint to be
15822 			 * there.  (No need to fix conislocal: ATTACH PARTITION does that)
15823 			 */
15824 			for (j = 0; j < tbinfo->ncheck; j++)
15825 			{
15826 				ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
15827 
15828 				if (constr->separate ||
15829 					(!constr->conislocal && !tbinfo->ispartition))
15830 					continue;
15831 
15832 				if (actual_atts == 0)
15833 					appendPQExpBufferStr(q, " (\n    ");
15834 				else
15835 					appendPQExpBufferStr(q, ",\n    ");
15836 
15837 				appendPQExpBuffer(q, "CONSTRAINT %s ",
15838 								  fmtId(constr->dobj.name));
15839 				appendPQExpBufferStr(q, constr->condef);
15840 
15841 				actual_atts++;
15842 			}
15843 
15844 			if (actual_atts)
15845 				appendPQExpBufferStr(q, "\n)");
15846 			else if (!(tbinfo->reloftype && !dopt->binary_upgrade))
15847 			{
15848 				/*
15849 				 * No attributes? we must have a parenthesized attribute list,
15850 				 * even though empty, when not using the OF TYPE syntax.
15851 				 */
15852 				appendPQExpBufferStr(q, " (\n)");
15853 			}
15854 
15855 			/*
15856 			 * Emit the INHERITS clause (not for partitions), except in
15857 			 * binary-upgrade mode.
15858 			 */
15859 			if (numParents > 0 && !tbinfo->ispartition &&
15860 				!dopt->binary_upgrade)
15861 			{
15862 				appendPQExpBufferStr(q, "\nINHERITS (");
15863 				for (k = 0; k < numParents; k++)
15864 				{
15865 					TableInfo  *parentRel = parents[k];
15866 
15867 					if (k > 0)
15868 						appendPQExpBufferStr(q, ", ");
15869 					appendPQExpBufferStr(q, fmtQualifiedDumpable(parentRel));
15870 				}
15871 				appendPQExpBufferChar(q, ')');
15872 			}
15873 
15874 			if (tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
15875 				appendPQExpBuffer(q, "\nPARTITION BY %s", tbinfo->partkeydef);
15876 
15877 			if (tbinfo->relkind == RELKIND_FOREIGN_TABLE)
15878 				appendPQExpBuffer(q, "\nSERVER %s", fmtId(srvname));
15879 		}
15880 
15881 		if (nonemptyReloptions(tbinfo->reloptions) ||
15882 			nonemptyReloptions(tbinfo->toast_reloptions))
15883 		{
15884 			bool		addcomma = false;
15885 
15886 			appendPQExpBufferStr(q, "\nWITH (");
15887 			if (nonemptyReloptions(tbinfo->reloptions))
15888 			{
15889 				addcomma = true;
15890 				appendReloptionsArrayAH(q, tbinfo->reloptions, "", fout);
15891 			}
15892 			if (nonemptyReloptions(tbinfo->toast_reloptions))
15893 			{
15894 				if (addcomma)
15895 					appendPQExpBufferStr(q, ", ");
15896 				appendReloptionsArrayAH(q, tbinfo->toast_reloptions, "toast.",
15897 										fout);
15898 			}
15899 			appendPQExpBufferChar(q, ')');
15900 		}
15901 
15902 		/* Dump generic options if any */
15903 		if (ftoptions && ftoptions[0])
15904 			appendPQExpBuffer(q, "\nOPTIONS (\n    %s\n)", ftoptions);
15905 
15906 		/*
15907 		 * For materialized views, create the AS clause just like a view. At
15908 		 * this point, we always mark the view as not populated.
15909 		 */
15910 		if (tbinfo->relkind == RELKIND_MATVIEW)
15911 		{
15912 			PQExpBuffer result;
15913 
15914 			result = createViewAsClause(fout, tbinfo);
15915 			appendPQExpBuffer(q, " AS\n%s\n  WITH NO DATA;\n",
15916 							  result->data);
15917 			destroyPQExpBuffer(result);
15918 		}
15919 		else
15920 			appendPQExpBufferStr(q, ";\n");
15921 
15922 		/* Materialized views can depend on extensions */
15923 		if (tbinfo->relkind == RELKIND_MATVIEW)
15924 			append_depends_on_extension(fout, q, &tbinfo->dobj,
15925 										"pg_catalog.pg_class",
15926 										tbinfo->relkind == RELKIND_MATVIEW ?
15927 										"MATERIALIZED VIEW" : "INDEX",
15928 										qualrelname);
15929 
15930 		/*
15931 		 * in binary upgrade mode, update the catalog with any missing values
15932 		 * that might be present.
15933 		 */
15934 		if (dopt->binary_upgrade)
15935 		{
15936 			for (j = 0; j < tbinfo->numatts; j++)
15937 			{
15938 				if (tbinfo->attmissingval[j][0] != '\0')
15939 				{
15940 					appendPQExpBufferStr(q, "\n-- set missing value.\n");
15941 					appendPQExpBufferStr(q,
15942 										 "SELECT pg_catalog.binary_upgrade_set_missing_value(");
15943 					appendStringLiteralAH(q, qualrelname, fout);
15944 					appendPQExpBufferStr(q, "::pg_catalog.regclass,");
15945 					appendStringLiteralAH(q, tbinfo->attnames[j], fout);
15946 					appendPQExpBufferStr(q, ",");
15947 					appendStringLiteralAH(q, tbinfo->attmissingval[j], fout);
15948 					appendPQExpBufferStr(q, ");\n\n");
15949 				}
15950 			}
15951 		}
15952 
15953 		/*
15954 		 * To create binary-compatible heap files, we have to ensure the same
15955 		 * physical column order, including dropped columns, as in the
15956 		 * original.  Therefore, we create dropped columns above and drop them
15957 		 * here, also updating their attlen/attalign values so that the
15958 		 * dropped column can be skipped properly.  (We do not bother with
15959 		 * restoring the original attbyval setting.)  Also, inheritance
15960 		 * relationships are set up by doing ALTER TABLE INHERIT rather than
15961 		 * using an INHERITS clause --- the latter would possibly mess up the
15962 		 * column order.  That also means we have to take care about setting
15963 		 * attislocal correctly, plus fix up any inherited CHECK constraints.
15964 		 * Analogously, we set up typed tables using ALTER TABLE / OF here.
15965 		 *
15966 		 * We process foreign and partitioned tables here, even though they
15967 		 * lack heap storage, because they can participate in inheritance
15968 		 * relationships and we want this stuff to be consistent across the
15969 		 * inheritance tree.  We can exclude indexes, toast tables, sequences
15970 		 * and matviews, even though they have storage, because we don't
15971 		 * support altering or dropping columns in them, nor can they be part
15972 		 * of inheritance trees.
15973 		 */
15974 		if (dopt->binary_upgrade &&
15975 			(tbinfo->relkind == RELKIND_RELATION ||
15976 			 tbinfo->relkind == RELKIND_FOREIGN_TABLE ||
15977 			 tbinfo->relkind == RELKIND_PARTITIONED_TABLE))
15978 		{
15979 			for (j = 0; j < tbinfo->numatts; j++)
15980 			{
15981 				if (tbinfo->attisdropped[j])
15982 				{
15983 					appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate dropped column.\n");
15984 					appendPQExpBuffer(q, "UPDATE pg_catalog.pg_attribute\n"
15985 									  "SET attlen = %d, "
15986 									  "attalign = '%c', attbyval = false\n"
15987 									  "WHERE attname = ",
15988 									  tbinfo->attlen[j],
15989 									  tbinfo->attalign[j]);
15990 					appendStringLiteralAH(q, tbinfo->attnames[j], fout);
15991 					appendPQExpBufferStr(q, "\n  AND attrelid = ");
15992 					appendStringLiteralAH(q, qualrelname, fout);
15993 					appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
15994 
15995 					if (tbinfo->relkind == RELKIND_RELATION ||
15996 						tbinfo->relkind == RELKIND_PARTITIONED_TABLE)
15997 						appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
15998 										  qualrelname);
15999 					else
16000 						appendPQExpBuffer(q, "ALTER FOREIGN TABLE ONLY %s ",
16001 										  qualrelname);
16002 					appendPQExpBuffer(q, "DROP COLUMN %s;\n",
16003 									  fmtId(tbinfo->attnames[j]));
16004 				}
16005 				else if (!tbinfo->attislocal[j])
16006 				{
16007 					appendPQExpBufferStr(q, "\n-- For binary upgrade, recreate inherited column.\n");
16008 					appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_attribute\n"
16009 										 "SET attislocal = false\n"
16010 										 "WHERE attname = ");
16011 					appendStringLiteralAH(q, tbinfo->attnames[j], fout);
16012 					appendPQExpBufferStr(q, "\n  AND attrelid = ");
16013 					appendStringLiteralAH(q, qualrelname, fout);
16014 					appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
16015 				}
16016 			}
16017 
16018 			/*
16019 			 * Add inherited CHECK constraints, if any.
16020 			 *
16021 			 * For partitions, they were already dumped, and conislocal
16022 			 * doesn't need fixing.
16023 			 */
16024 			for (k = 0; k < tbinfo->ncheck; k++)
16025 			{
16026 				ConstraintInfo *constr = &(tbinfo->checkexprs[k]);
16027 
16028 				if (constr->separate || constr->conislocal || tbinfo->ispartition)
16029 					continue;
16030 
16031 				appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inherited constraint.\n");
16032 				appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
16033 								  qualrelname);
16034 				appendPQExpBuffer(q, " ADD CONSTRAINT %s ",
16035 								  fmtId(constr->dobj.name));
16036 				appendPQExpBuffer(q, "%s;\n", constr->condef);
16037 				appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_constraint\n"
16038 									 "SET conislocal = false\n"
16039 									 "WHERE contype = 'c' AND conname = ");
16040 				appendStringLiteralAH(q, constr->dobj.name, fout);
16041 				appendPQExpBufferStr(q, "\n  AND conrelid = ");
16042 				appendStringLiteralAH(q, qualrelname, fout);
16043 				appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
16044 			}
16045 
16046 			if (numParents > 0 && !tbinfo->ispartition)
16047 			{
16048 				appendPQExpBufferStr(q, "\n-- For binary upgrade, set up inheritance this way.\n");
16049 				for (k = 0; k < numParents; k++)
16050 				{
16051 					TableInfo  *parentRel = parents[k];
16052 
16053 					appendPQExpBuffer(q, "ALTER TABLE ONLY %s INHERIT %s;\n",
16054 									  qualrelname,
16055 									  fmtQualifiedDumpable(parentRel));
16056 				}
16057 			}
16058 
16059 			if (tbinfo->reloftype)
16060 			{
16061 				appendPQExpBufferStr(q, "\n-- For binary upgrade, set up typed tables this way.\n");
16062 				appendPQExpBuffer(q, "ALTER TABLE ONLY %s OF %s;\n",
16063 								  qualrelname,
16064 								  tbinfo->reloftype);
16065 			}
16066 		}
16067 
16068 		/*
16069 		 * For partitioned tables, emit the ATTACH PARTITION clause.  Note
16070 		 * that we always want to create partitions this way instead of using
16071 		 * CREATE TABLE .. PARTITION OF, mainly to preserve a possible column
16072 		 * layout discrepancy with the parent, but also to ensure it gets the
16073 		 * correct tablespace setting if it differs from the parent's.
16074 		 */
16075 		if (tbinfo->ispartition)
16076 		{
16077 			/* With partitions there can only be one parent */
16078 			if (tbinfo->numParents != 1)
16079 				exit_horribly(NULL, "invalid number of parents %d for table \"%s\"\n",
16080 					  tbinfo->numParents, tbinfo->dobj.name);
16081 
16082 			/* Perform ALTER TABLE on the parent */
16083 			appendPQExpBuffer(q,
16084 							  "ALTER TABLE ONLY %s ATTACH PARTITION %s %s;\n",
16085 							  fmtQualifiedDumpable(parents[0]),
16086 							  qualrelname, tbinfo->partbound);
16087 		}
16088 
16089 		/*
16090 		 * In binary_upgrade mode, arrange to restore the old relfrozenxid and
16091 		 * relminmxid of all vacuumable relations.  (While vacuum.c processes
16092 		 * TOAST tables semi-independently, here we see them only as children
16093 		 * of other relations; so this "if" lacks RELKIND_TOASTVALUE, and the
16094 		 * child toast table is handled below.)
16095 		 */
16096 		if (dopt->binary_upgrade &&
16097 			(tbinfo->relkind == RELKIND_RELATION ||
16098 			 tbinfo->relkind == RELKIND_MATVIEW))
16099 		{
16100 			appendPQExpBufferStr(q, "\n-- For binary upgrade, set heap's relfrozenxid and relminmxid\n");
16101 			appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
16102 							  "SET relfrozenxid = '%u', relminmxid = '%u'\n"
16103 							  "WHERE oid = ",
16104 							  tbinfo->frozenxid, tbinfo->minmxid);
16105 			appendStringLiteralAH(q, qualrelname, fout);
16106 			appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
16107 
16108 			if (tbinfo->toast_oid)
16109 			{
16110 				/*
16111 				 * The toast table will have the same OID at restore, so we
16112 				 * can safely target it by OID.
16113 				 */
16114 				appendPQExpBufferStr(q, "\n-- For binary upgrade, set toast's relfrozenxid and relminmxid\n");
16115 				appendPQExpBuffer(q, "UPDATE pg_catalog.pg_class\n"
16116 								  "SET relfrozenxid = '%u', relminmxid = '%u'\n"
16117 								  "WHERE oid = '%u';\n",
16118 								  tbinfo->toast_frozenxid,
16119 								  tbinfo->toast_minmxid, tbinfo->toast_oid);
16120 			}
16121 		}
16122 
16123 		/*
16124 		 * In binary_upgrade mode, restore matviews' populated status by
16125 		 * poking pg_class directly.  This is pretty ugly, but we can't use
16126 		 * REFRESH MATERIALIZED VIEW since it's possible that some underlying
16127 		 * matview is not populated even though this matview is; in any case,
16128 		 * we want to transfer the matview's heap storage, not run REFRESH.
16129 		 */
16130 		if (dopt->binary_upgrade && tbinfo->relkind == RELKIND_MATVIEW &&
16131 			tbinfo->relispopulated)
16132 		{
16133 			appendPQExpBufferStr(q, "\n-- For binary upgrade, mark materialized view as populated\n");
16134 			appendPQExpBufferStr(q, "UPDATE pg_catalog.pg_class\n"
16135 								 "SET relispopulated = 't'\n"
16136 								 "WHERE oid = ");
16137 			appendStringLiteralAH(q, qualrelname, fout);
16138 			appendPQExpBufferStr(q, "::pg_catalog.regclass;\n");
16139 		}
16140 
16141 		/*
16142 		 * Dump additional per-column properties that we can't handle in the
16143 		 * main CREATE TABLE command.
16144 		 */
16145 		for (j = 0; j < tbinfo->numatts; j++)
16146 		{
16147 			/* None of this applies to dropped columns */
16148 			if (tbinfo->attisdropped[j])
16149 				continue;
16150 
16151 			/*
16152 			 * If we didn't dump the column definition explicitly above, and
16153 			 * it is NOT NULL and did not inherit that property from a parent,
16154 			 * we have to mark it separately.
16155 			 */
16156 			if (!shouldPrintColumn(dopt, tbinfo, j) &&
16157 				tbinfo->notnull[j] && !tbinfo->inhNotNull[j])
16158 			{
16159 				appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
16160 								  qualrelname);
16161 				appendPQExpBuffer(q, "ALTER COLUMN %s SET NOT NULL;\n",
16162 								  fmtId(tbinfo->attnames[j]));
16163 			}
16164 
16165 			/*
16166 			 * Dump per-column statistics information. We only issue an ALTER
16167 			 * TABLE statement if the attstattarget entry for this column is
16168 			 * non-negative (i.e. it's not the default value)
16169 			 */
16170 			if (tbinfo->attstattarget[j] >= 0)
16171 			{
16172 				appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
16173 								  qualrelname);
16174 				appendPQExpBuffer(q, "ALTER COLUMN %s ",
16175 								  fmtId(tbinfo->attnames[j]));
16176 				appendPQExpBuffer(q, "SET STATISTICS %d;\n",
16177 								  tbinfo->attstattarget[j]);
16178 			}
16179 
16180 			/*
16181 			 * Dump per-column storage information.  The statement is only
16182 			 * dumped if the storage has been changed from the type's default.
16183 			 */
16184 			if (tbinfo->attstorage[j] != tbinfo->typstorage[j])
16185 			{
16186 				switch (tbinfo->attstorage[j])
16187 				{
16188 					case 'p':
16189 						storage = "PLAIN";
16190 						break;
16191 					case 'e':
16192 						storage = "EXTERNAL";
16193 						break;
16194 					case 'm':
16195 						storage = "MAIN";
16196 						break;
16197 					case 'x':
16198 						storage = "EXTENDED";
16199 						break;
16200 					default:
16201 						storage = NULL;
16202 				}
16203 
16204 				/*
16205 				 * Only dump the statement if it's a storage type we recognize
16206 				 */
16207 				if (storage != NULL)
16208 				{
16209 					appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
16210 									  qualrelname);
16211 					appendPQExpBuffer(q, "ALTER COLUMN %s ",
16212 									  fmtId(tbinfo->attnames[j]));
16213 					appendPQExpBuffer(q, "SET STORAGE %s;\n",
16214 									  storage);
16215 				}
16216 			}
16217 
16218 			/*
16219 			 * Dump per-column attributes.
16220 			 */
16221 			if (tbinfo->attoptions[j] && tbinfo->attoptions[j][0] != '\0')
16222 			{
16223 				appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
16224 								  qualrelname);
16225 				appendPQExpBuffer(q, "ALTER COLUMN %s ",
16226 								  fmtId(tbinfo->attnames[j]));
16227 				appendPQExpBuffer(q, "SET (%s);\n",
16228 								  tbinfo->attoptions[j]);
16229 			}
16230 
16231 			/*
16232 			 * Dump per-column fdw options.
16233 			 */
16234 			if (tbinfo->relkind == RELKIND_FOREIGN_TABLE &&
16235 				tbinfo->attfdwoptions[j] &&
16236 				tbinfo->attfdwoptions[j][0] != '\0')
16237 			{
16238 				appendPQExpBuffer(q, "ALTER FOREIGN TABLE %s ",
16239 								  qualrelname);
16240 				appendPQExpBuffer(q, "ALTER COLUMN %s ",
16241 								  fmtId(tbinfo->attnames[j]));
16242 				appendPQExpBuffer(q, "OPTIONS (\n    %s\n);\n",
16243 								  tbinfo->attfdwoptions[j]);
16244 			}
16245 		}
16246 	}
16247 
16248 	/*
16249 	 * dump properties we only have ALTER TABLE syntax for
16250 	 */
16251 	if ((tbinfo->relkind == RELKIND_RELATION ||
16252 		 tbinfo->relkind == RELKIND_PARTITIONED_TABLE ||
16253 		 tbinfo->relkind == RELKIND_MATVIEW) &&
16254 		tbinfo->relreplident != REPLICA_IDENTITY_DEFAULT)
16255 	{
16256 		if (tbinfo->relreplident == REPLICA_IDENTITY_INDEX)
16257 		{
16258 			/* nothing to do, will be set when the index is dumped */
16259 		}
16260 		else if (tbinfo->relreplident == REPLICA_IDENTITY_NOTHING)
16261 		{
16262 			appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY NOTHING;\n",
16263 							  qualrelname);
16264 		}
16265 		else if (tbinfo->relreplident == REPLICA_IDENTITY_FULL)
16266 		{
16267 			appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY FULL;\n",
16268 							  qualrelname);
16269 		}
16270 	}
16271 
16272 	if (tbinfo->relkind == RELKIND_FOREIGN_TABLE && tbinfo->hasoids)
16273 		appendPQExpBuffer(q, "\nALTER TABLE ONLY %s SET WITH OIDS;\n",
16274 						  qualrelname);
16275 
16276 	if (tbinfo->forcerowsec)
16277 		appendPQExpBuffer(q, "\nALTER TABLE ONLY %s FORCE ROW LEVEL SECURITY;\n",
16278 						  qualrelname);
16279 
16280 	if (dopt->binary_upgrade)
16281 		binary_upgrade_extension_member(q, &tbinfo->dobj,
16282 										reltypename, qrelname,
16283 										tbinfo->dobj.namespace->dobj.name);
16284 
16285 	if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16286 		ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
16287 					 tbinfo->dobj.name,
16288 					 tbinfo->dobj.namespace->dobj.name,
16289 					 (tbinfo->relkind == RELKIND_VIEW) ? NULL : tbinfo->reltablespace,
16290 					 tbinfo->rolname,
16291 					 (strcmp(reltypename, "TABLE") == 0) ? tbinfo->hasoids : false,
16292 					 reltypename,
16293 					 tbinfo->postponed_def ?
16294 					 SECTION_POST_DATA : SECTION_PRE_DATA,
16295 					 q->data, delq->data, NULL,
16296 					 NULL, 0,
16297 					 NULL, NULL);
16298 
16299 
16300 	/* Dump Table Comments */
16301 	if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16302 		dumpTableComment(fout, tbinfo, reltypename);
16303 
16304 	/* Dump Table Security Labels */
16305 	if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
16306 		dumpTableSecLabel(fout, tbinfo, reltypename);
16307 
16308 	/* Dump comments on inlined table constraints */
16309 	for (j = 0; j < tbinfo->ncheck; j++)
16310 	{
16311 		ConstraintInfo *constr = &(tbinfo->checkexprs[j]);
16312 
16313 		if (constr->separate || !constr->conislocal)
16314 			continue;
16315 
16316 		if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16317 			dumpTableConstraintComment(fout, constr);
16318 	}
16319 
16320 	destroyPQExpBuffer(q);
16321 	destroyPQExpBuffer(delq);
16322 	free(qrelname);
16323 	free(qualrelname);
16324 }
16325 
16326 /*
16327  * dumpAttrDef --- dump an attribute's default-value declaration
16328  */
16329 static void
dumpAttrDef(Archive * fout,AttrDefInfo * adinfo)16330 dumpAttrDef(Archive *fout, AttrDefInfo *adinfo)
16331 {
16332 	DumpOptions *dopt = fout->dopt;
16333 	TableInfo  *tbinfo = adinfo->adtable;
16334 	int			adnum = adinfo->adnum;
16335 	PQExpBuffer q;
16336 	PQExpBuffer delq;
16337 	char	   *qualrelname;
16338 	char	   *tag;
16339 
16340 	/* Skip if table definition not to be dumped */
16341 	if (!tbinfo->dobj.dump || dopt->dataOnly)
16342 		return;
16343 
16344 	/* Skip if not "separate"; it was dumped in the table's definition */
16345 	if (!adinfo->separate)
16346 		return;
16347 
16348 	q = createPQExpBuffer();
16349 	delq = createPQExpBuffer();
16350 
16351 	qualrelname = pg_strdup(fmtQualifiedDumpable(tbinfo));
16352 
16353 	appendPQExpBuffer(q, "ALTER TABLE ONLY %s ",
16354 					  qualrelname);
16355 	appendPQExpBuffer(q, "ALTER COLUMN %s SET DEFAULT %s;\n",
16356 					  fmtId(tbinfo->attnames[adnum - 1]),
16357 					  adinfo->adef_expr);
16358 
16359 	appendPQExpBuffer(delq, "ALTER TABLE %s ",
16360 					  qualrelname);
16361 	appendPQExpBuffer(delq, "ALTER COLUMN %s DROP DEFAULT;\n",
16362 					  fmtId(tbinfo->attnames[adnum - 1]));
16363 
16364 	tag = psprintf("%s %s", tbinfo->dobj.name, tbinfo->attnames[adnum - 1]);
16365 
16366 	if (adinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16367 		ArchiveEntry(fout, adinfo->dobj.catId, adinfo->dobj.dumpId,
16368 					 tag,
16369 					 tbinfo->dobj.namespace->dobj.name,
16370 					 NULL,
16371 					 tbinfo->rolname,
16372 					 false, "DEFAULT", SECTION_PRE_DATA,
16373 					 q->data, delq->data, NULL,
16374 					 NULL, 0,
16375 					 NULL, NULL);
16376 
16377 	free(tag);
16378 	destroyPQExpBuffer(q);
16379 	destroyPQExpBuffer(delq);
16380 	free(qualrelname);
16381 }
16382 
16383 /*
16384  * getAttrName: extract the correct name for an attribute
16385  *
16386  * The array tblInfo->attnames[] only provides names of user attributes;
16387  * if a system attribute number is supplied, we have to fake it.
16388  * We also do a little bit of bounds checking for safety's sake.
16389  */
16390 static const char *
getAttrName(int attrnum,TableInfo * tblInfo)16391 getAttrName(int attrnum, TableInfo *tblInfo)
16392 {
16393 	if (attrnum > 0 && attrnum <= tblInfo->numatts)
16394 		return tblInfo->attnames[attrnum - 1];
16395 	switch (attrnum)
16396 	{
16397 		case SelfItemPointerAttributeNumber:
16398 			return "ctid";
16399 		case ObjectIdAttributeNumber:
16400 			return "oid";
16401 		case MinTransactionIdAttributeNumber:
16402 			return "xmin";
16403 		case MinCommandIdAttributeNumber:
16404 			return "cmin";
16405 		case MaxTransactionIdAttributeNumber:
16406 			return "xmax";
16407 		case MaxCommandIdAttributeNumber:
16408 			return "cmax";
16409 		case TableOidAttributeNumber:
16410 			return "tableoid";
16411 	}
16412 	exit_horribly(NULL, "invalid column number %d for table \"%s\"\n",
16413 				  attrnum, tblInfo->dobj.name);
16414 	return NULL;				/* keep compiler quiet */
16415 }
16416 
16417 /*
16418  * dumpIndex
16419  *	  write out to fout a user-defined index
16420  */
16421 static void
dumpIndex(Archive * fout,IndxInfo * indxinfo)16422 dumpIndex(Archive *fout, IndxInfo *indxinfo)
16423 {
16424 	DumpOptions *dopt = fout->dopt;
16425 	TableInfo  *tbinfo = indxinfo->indextable;
16426 	bool		is_constraint = (indxinfo->indexconstraint != 0);
16427 	PQExpBuffer q;
16428 	PQExpBuffer delq;
16429 	char	   *qindxname;
16430 	char	   *qqindxname;
16431 
16432 	if (dopt->dataOnly)
16433 		return;
16434 
16435 	q = createPQExpBuffer();
16436 	delq = createPQExpBuffer();
16437 
16438 	qindxname = pg_strdup(fmtId(indxinfo->dobj.name));
16439 	qqindxname = pg_strdup(fmtQualifiedDumpable(indxinfo));
16440 
16441 	/*
16442 	 * If there's an associated constraint, don't dump the index per se, but
16443 	 * do dump any comment for it.  (This is safe because dependency ordering
16444 	 * will have ensured the constraint is emitted first.)	Note that the
16445 	 * emitted comment has to be shown as depending on the constraint, not the
16446 	 * index, in such cases.
16447 	 */
16448 	if (!is_constraint)
16449 	{
16450 		char	   *indstatcols = indxinfo->indstatcols;
16451 		char	   *indstatvals = indxinfo->indstatvals;
16452 		char	  **indstatcolsarray = NULL;
16453 		char	  **indstatvalsarray = NULL;
16454 		int			nstatcols;
16455 		int			nstatvals;
16456 
16457 		if (dopt->binary_upgrade)
16458 			binary_upgrade_set_pg_class_oids(fout, q,
16459 											 indxinfo->dobj.catId.oid, true);
16460 
16461 		/* Plain secondary index */
16462 		appendPQExpBuffer(q, "%s;\n", indxinfo->indexdef);
16463 
16464 		/*
16465 		 * Append ALTER TABLE commands as needed to set properties that we
16466 		 * only have ALTER TABLE syntax for.  Keep this in sync with the
16467 		 * similar code in dumpConstraint!
16468 		 */
16469 
16470 		/* If the index is clustered, we need to record that. */
16471 		if (indxinfo->indisclustered)
16472 		{
16473 			appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
16474 							  fmtQualifiedDumpable(tbinfo));
16475 			/* index name is not qualified in this syntax */
16476 			appendPQExpBuffer(q, " ON %s;\n",
16477 							  qindxname);
16478 		}
16479 
16480 		/*
16481 		 * If the index has any statistics on some of its columns, generate
16482 		 * the associated ALTER INDEX queries.
16483 		 */
16484 		if (parsePGArray(indstatcols, &indstatcolsarray, &nstatcols) &&
16485 			parsePGArray(indstatvals, &indstatvalsarray, &nstatvals) &&
16486 			nstatcols == nstatvals)
16487 		{
16488 			int			j;
16489 
16490 			for (j = 0; j < nstatcols; j++)
16491 			{
16492 				appendPQExpBuffer(q, "ALTER INDEX %s ", qqindxname);
16493 
16494 				/*
16495 				 * Note that this is a column number, so no quotes should be
16496 				 * used.
16497 				 */
16498 				appendPQExpBuffer(q, "ALTER COLUMN %s ",
16499 								  indstatcolsarray[j]);
16500 				appendPQExpBuffer(q, "SET STATISTICS %s;\n",
16501 								  indstatvalsarray[j]);
16502 			}
16503 		}
16504 
16505 		/* Indexes can depend on extensions */
16506 		append_depends_on_extension(fout, q, &indxinfo->dobj,
16507 									"pg_catalog.pg_class",
16508 									"INDEX", qqindxname);
16509 
16510 		/* If the index defines identity, we need to record that. */
16511 		if (indxinfo->indisreplident)
16512 		{
16513 			appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
16514 							  fmtQualifiedDumpable(tbinfo));
16515 			/* index name is not qualified in this syntax */
16516 			appendPQExpBuffer(q, " INDEX %s;\n",
16517 							  qindxname);
16518 		}
16519 
16520 		appendPQExpBuffer(delq, "DROP INDEX %s;\n", qqindxname);
16521 
16522 		if (indxinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16523 			ArchiveEntry(fout, indxinfo->dobj.catId, indxinfo->dobj.dumpId,
16524 						 indxinfo->dobj.name,
16525 						 tbinfo->dobj.namespace->dobj.name,
16526 						 indxinfo->tablespace,
16527 						 tbinfo->rolname, false,
16528 						 "INDEX", SECTION_POST_DATA,
16529 						 q->data, delq->data, NULL,
16530 						 NULL, 0,
16531 						 NULL, NULL);
16532 
16533 		if (indstatcolsarray)
16534 			free(indstatcolsarray);
16535 		if (indstatvalsarray)
16536 			free(indstatvalsarray);
16537 	}
16538 
16539 	/* Dump Index Comments */
16540 	if (indxinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16541 		dumpComment(fout, "INDEX", qindxname,
16542 					tbinfo->dobj.namespace->dobj.name,
16543 					tbinfo->rolname,
16544 					indxinfo->dobj.catId, 0,
16545 					is_constraint ? indxinfo->indexconstraint :
16546 					indxinfo->dobj.dumpId);
16547 
16548 	destroyPQExpBuffer(q);
16549 	destroyPQExpBuffer(delq);
16550 	free(qindxname);
16551 	free(qqindxname);
16552 }
16553 
16554 /*
16555  * dumpIndexAttach
16556  *	  write out to fout a partitioned-index attachment clause
16557  */
16558 static void
dumpIndexAttach(Archive * fout,IndexAttachInfo * attachinfo)16559 dumpIndexAttach(Archive *fout, IndexAttachInfo *attachinfo)
16560 {
16561 	if (fout->dopt->dataOnly)
16562 		return;
16563 
16564 	if (attachinfo->partitionIdx->dobj.dump & DUMP_COMPONENT_DEFINITION)
16565 	{
16566 		PQExpBuffer q = createPQExpBuffer();
16567 
16568 		appendPQExpBuffer(q, "ALTER INDEX %s ",
16569 						  fmtQualifiedDumpable(attachinfo->parentIdx));
16570 		appendPQExpBuffer(q, "ATTACH PARTITION %s;\n",
16571 						  fmtQualifiedDumpable(attachinfo->partitionIdx));
16572 
16573 		ArchiveEntry(fout, attachinfo->dobj.catId, attachinfo->dobj.dumpId,
16574 					 attachinfo->dobj.name,
16575 					 attachinfo->dobj.namespace->dobj.name,
16576 					 NULL,
16577 					 attachinfo->parentIdx->indextable->rolname,
16578 					 false, "INDEX ATTACH", SECTION_POST_DATA,
16579 					 q->data, "", NULL,
16580 					 NULL, 0,
16581 					 NULL, NULL);
16582 
16583 		destroyPQExpBuffer(q);
16584 	}
16585 }
16586 
16587 /*
16588  * dumpStatisticsExt
16589  *	  write out to fout an extended statistics object
16590  */
16591 static void
dumpStatisticsExt(Archive * fout,StatsExtInfo * statsextinfo)16592 dumpStatisticsExt(Archive *fout, StatsExtInfo *statsextinfo)
16593 {
16594 	DumpOptions *dopt = fout->dopt;
16595 	PQExpBuffer q;
16596 	PQExpBuffer delq;
16597 	PQExpBuffer query;
16598 	char	   *qstatsextname;
16599 	PGresult   *res;
16600 	char	   *stxdef;
16601 
16602 	/* Skip if not to be dumped */
16603 	if (!statsextinfo->dobj.dump || dopt->dataOnly)
16604 		return;
16605 
16606 	q = createPQExpBuffer();
16607 	delq = createPQExpBuffer();
16608 	query = createPQExpBuffer();
16609 
16610 	qstatsextname = pg_strdup(fmtId(statsextinfo->dobj.name));
16611 
16612 	appendPQExpBuffer(query, "SELECT "
16613 					  "pg_catalog.pg_get_statisticsobjdef('%u'::pg_catalog.oid)",
16614 					  statsextinfo->dobj.catId.oid);
16615 
16616 	res = ExecuteSqlQueryForSingleRow(fout, query->data);
16617 
16618 	stxdef = PQgetvalue(res, 0, 0);
16619 
16620 	/* Result of pg_get_statisticsobjdef is complete except for semicolon */
16621 	appendPQExpBuffer(q, "%s;\n", stxdef);
16622 
16623 	appendPQExpBuffer(delq, "DROP STATISTICS %s;\n",
16624 					  fmtQualifiedDumpable(statsextinfo));
16625 
16626 	if (statsextinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16627 		ArchiveEntry(fout, statsextinfo->dobj.catId,
16628 					 statsextinfo->dobj.dumpId,
16629 					 statsextinfo->dobj.name,
16630 					 statsextinfo->dobj.namespace->dobj.name,
16631 					 NULL,
16632 					 statsextinfo->rolname, false,
16633 					 "STATISTICS", SECTION_POST_DATA,
16634 					 q->data, delq->data, NULL,
16635 					 NULL, 0,
16636 					 NULL, NULL);
16637 
16638 	/* Dump Statistics Comments */
16639 	if (statsextinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16640 		dumpComment(fout, "STATISTICS", qstatsextname,
16641 					statsextinfo->dobj.namespace->dobj.name,
16642 					statsextinfo->rolname,
16643 					statsextinfo->dobj.catId, 0,
16644 					statsextinfo->dobj.dumpId);
16645 
16646 	PQclear(res);
16647 	destroyPQExpBuffer(q);
16648 	destroyPQExpBuffer(delq);
16649 	destroyPQExpBuffer(query);
16650 	free(qstatsextname);
16651 }
16652 
16653 /*
16654  * dumpConstraint
16655  *	  write out to fout a user-defined constraint
16656  */
16657 static void
dumpConstraint(Archive * fout,ConstraintInfo * coninfo)16658 dumpConstraint(Archive *fout, ConstraintInfo *coninfo)
16659 {
16660 	DumpOptions *dopt = fout->dopt;
16661 	TableInfo  *tbinfo = coninfo->contable;
16662 	PQExpBuffer q;
16663 	PQExpBuffer delq;
16664 	char	   *tag = NULL;
16665 
16666 	/* Skip if not to be dumped */
16667 	if (!coninfo->dobj.dump || dopt->dataOnly)
16668 		return;
16669 
16670 	q = createPQExpBuffer();
16671 	delq = createPQExpBuffer();
16672 
16673 	if (coninfo->contype == 'p' ||
16674 		coninfo->contype == 'u' ||
16675 		coninfo->contype == 'x')
16676 	{
16677 		/* Index-related constraint */
16678 		IndxInfo   *indxinfo;
16679 		int			k;
16680 
16681 		indxinfo = (IndxInfo *) findObjectByDumpId(coninfo->conindex);
16682 
16683 		if (indxinfo == NULL)
16684 			exit_horribly(NULL, "missing index for constraint \"%s\"\n",
16685 						  coninfo->dobj.name);
16686 
16687 		if (dopt->binary_upgrade)
16688 			binary_upgrade_set_pg_class_oids(fout, q,
16689 											 indxinfo->dobj.catId.oid, true);
16690 
16691 		appendPQExpBuffer(q, "ALTER TABLE ONLY %s\n",
16692 						  fmtQualifiedDumpable(tbinfo));
16693 		appendPQExpBuffer(q, "    ADD CONSTRAINT %s ",
16694 						  fmtId(coninfo->dobj.name));
16695 
16696 		if (coninfo->condef)
16697 		{
16698 			/* pg_get_constraintdef should have provided everything */
16699 			appendPQExpBuffer(q, "%s;\n", coninfo->condef);
16700 		}
16701 		else
16702 		{
16703 			appendPQExpBuffer(q, "%s (",
16704 							  coninfo->contype == 'p' ? "PRIMARY KEY" : "UNIQUE");
16705 			for (k = 0; k < indxinfo->indnkeyattrs; k++)
16706 			{
16707 				int			indkey = (int) indxinfo->indkeys[k];
16708 				const char *attname;
16709 
16710 				if (indkey == InvalidAttrNumber)
16711 					break;
16712 				attname = getAttrName(indkey, tbinfo);
16713 
16714 				appendPQExpBuffer(q, "%s%s",
16715 								  (k == 0) ? "" : ", ",
16716 								  fmtId(attname));
16717 			}
16718 
16719 			if (indxinfo->indnkeyattrs < indxinfo->indnattrs)
16720 				appendPQExpBuffer(q, ") INCLUDE (");
16721 
16722 			for (k = indxinfo->indnkeyattrs; k < indxinfo->indnattrs; k++)
16723 			{
16724 				int			indkey = (int) indxinfo->indkeys[k];
16725 				const char *attname;
16726 
16727 				if (indkey == InvalidAttrNumber)
16728 					break;
16729 				attname = getAttrName(indkey, tbinfo);
16730 
16731 				appendPQExpBuffer(q, "%s%s",
16732 								  (k == indxinfo->indnkeyattrs) ? "" : ", ",
16733 								  fmtId(attname));
16734 			}
16735 
16736 			appendPQExpBufferChar(q, ')');
16737 
16738 			if (nonemptyReloptions(indxinfo->indreloptions))
16739 			{
16740 				appendPQExpBufferStr(q, " WITH (");
16741 				appendReloptionsArrayAH(q, indxinfo->indreloptions, "", fout);
16742 				appendPQExpBufferChar(q, ')');
16743 			}
16744 
16745 			if (coninfo->condeferrable)
16746 			{
16747 				appendPQExpBufferStr(q, " DEFERRABLE");
16748 				if (coninfo->condeferred)
16749 					appendPQExpBufferStr(q, " INITIALLY DEFERRED");
16750 			}
16751 
16752 			appendPQExpBufferStr(q, ";\n");
16753 		}
16754 
16755 		/*
16756 		 * Append ALTER TABLE commands as needed to set properties that we
16757 		 * only have ALTER TABLE syntax for.  Keep this in sync with the
16758 		 * similar code in dumpIndex!
16759 		 */
16760 
16761 		/* If the index is clustered, we need to record that. */
16762 		if (indxinfo->indisclustered)
16763 		{
16764 			appendPQExpBuffer(q, "\nALTER TABLE %s CLUSTER",
16765 							  fmtQualifiedDumpable(tbinfo));
16766 			/* index name is not qualified in this syntax */
16767 			appendPQExpBuffer(q, " ON %s;\n",
16768 							  fmtId(indxinfo->dobj.name));
16769 		}
16770 
16771 		/* If the index defines identity, we need to record that. */
16772 		if (indxinfo->indisreplident)
16773 		{
16774 			appendPQExpBuffer(q, "\nALTER TABLE ONLY %s REPLICA IDENTITY USING",
16775 							  fmtQualifiedDumpable(tbinfo));
16776 			/* index name is not qualified in this syntax */
16777 			appendPQExpBuffer(q, " INDEX %s;\n",
16778 							  fmtId(indxinfo->dobj.name));
16779 		}
16780 
16781 		/* Indexes can depend on extensions */
16782 		append_depends_on_extension(fout, q, &indxinfo->dobj,
16783 									"pg_catalog.pg_class", "INDEX",
16784 									fmtQualifiedDumpable(indxinfo));
16785 
16786 		appendPQExpBuffer(delq, "ALTER TABLE ONLY %s ",
16787 						  fmtQualifiedDumpable(tbinfo));
16788 		appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16789 						  fmtId(coninfo->dobj.name));
16790 
16791 		tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
16792 
16793 		if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16794 			ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16795 						 tag,
16796 						 tbinfo->dobj.namespace->dobj.name,
16797 						 indxinfo->tablespace,
16798 						 tbinfo->rolname, false,
16799 						 "CONSTRAINT", SECTION_POST_DATA,
16800 						 q->data, delq->data, NULL,
16801 						 NULL, 0,
16802 						 NULL, NULL);
16803 	}
16804 	else if (coninfo->contype == 'f')
16805 	{
16806 		char	   *only;
16807 
16808 		/*
16809 		 * Foreign keys on partitioned tables are always declared as
16810 		 * inheriting to partitions; for all other cases, emit them as
16811 		 * applying ONLY directly to the named table, because that's how they
16812 		 * work for regular inherited tables.
16813 		 */
16814 		only = tbinfo->relkind == RELKIND_PARTITIONED_TABLE ? "" : "ONLY ";
16815 
16816 		/*
16817 		 * XXX Potentially wrap in a 'SET CONSTRAINTS OFF' block so that the
16818 		 * current table data is not processed
16819 		 */
16820 		appendPQExpBuffer(q, "ALTER TABLE %s%s\n",
16821 						  only, fmtQualifiedDumpable(tbinfo));
16822 		appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
16823 						  fmtId(coninfo->dobj.name),
16824 						  coninfo->condef);
16825 
16826 		appendPQExpBuffer(delq, "ALTER TABLE %s%s ",
16827 						  only, fmtQualifiedDumpable(tbinfo));
16828 		appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16829 						  fmtId(coninfo->dobj.name));
16830 
16831 		tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
16832 
16833 		if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16834 			ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16835 						 tag,
16836 						 tbinfo->dobj.namespace->dobj.name,
16837 						 NULL,
16838 						 tbinfo->rolname, false,
16839 						 "FK CONSTRAINT", SECTION_POST_DATA,
16840 						 q->data, delq->data, NULL,
16841 						 NULL, 0,
16842 						 NULL, NULL);
16843 	}
16844 	else if (coninfo->contype == 'c' && tbinfo)
16845 	{
16846 		/* CHECK constraint on a table */
16847 
16848 		/* Ignore if not to be dumped separately, or if it was inherited */
16849 		if (coninfo->separate && coninfo->conislocal)
16850 		{
16851 			/* not ONLY since we want it to propagate to children */
16852 			appendPQExpBuffer(q, "ALTER TABLE %s\n",
16853 							  fmtQualifiedDumpable(tbinfo));
16854 			appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
16855 							  fmtId(coninfo->dobj.name),
16856 							  coninfo->condef);
16857 
16858 			appendPQExpBuffer(delq, "ALTER TABLE %s ",
16859 							  fmtQualifiedDumpable(tbinfo));
16860 			appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16861 							  fmtId(coninfo->dobj.name));
16862 
16863 			tag = psprintf("%s %s", tbinfo->dobj.name, coninfo->dobj.name);
16864 
16865 			if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16866 				ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16867 							 tag,
16868 							 tbinfo->dobj.namespace->dobj.name,
16869 							 NULL,
16870 							 tbinfo->rolname, false,
16871 							 "CHECK CONSTRAINT", SECTION_POST_DATA,
16872 							 q->data, delq->data, NULL,
16873 							 NULL, 0,
16874 							 NULL, NULL);
16875 		}
16876 	}
16877 	else if (coninfo->contype == 'c' && tbinfo == NULL)
16878 	{
16879 		/* CHECK constraint on a domain */
16880 		TypeInfo   *tyinfo = coninfo->condomain;
16881 
16882 		/* Ignore if not to be dumped separately */
16883 		if (coninfo->separate)
16884 		{
16885 			appendPQExpBuffer(q, "ALTER DOMAIN %s\n",
16886 							  fmtQualifiedDumpable(tyinfo));
16887 			appendPQExpBuffer(q, "    ADD CONSTRAINT %s %s;\n",
16888 							  fmtId(coninfo->dobj.name),
16889 							  coninfo->condef);
16890 
16891 			appendPQExpBuffer(delq, "ALTER DOMAIN %s ",
16892 							  fmtQualifiedDumpable(tyinfo));
16893 			appendPQExpBuffer(delq, "DROP CONSTRAINT %s;\n",
16894 							  fmtId(coninfo->dobj.name));
16895 
16896 			tag = psprintf("%s %s", tyinfo->dobj.name, coninfo->dobj.name);
16897 
16898 			if (coninfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
16899 				ArchiveEntry(fout, coninfo->dobj.catId, coninfo->dobj.dumpId,
16900 							 tag,
16901 							 tyinfo->dobj.namespace->dobj.name,
16902 							 NULL,
16903 							 tyinfo->rolname, false,
16904 							 "CHECK CONSTRAINT", SECTION_POST_DATA,
16905 							 q->data, delq->data, NULL,
16906 							 NULL, 0,
16907 							 NULL, NULL);
16908 		}
16909 	}
16910 	else
16911 	{
16912 		exit_horribly(NULL, "unrecognized constraint type: %c\n",
16913 					  coninfo->contype);
16914 	}
16915 
16916 	/* Dump Constraint Comments --- only works for table constraints */
16917 	if (tbinfo && coninfo->separate &&
16918 		coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16919 		dumpTableConstraintComment(fout, coninfo);
16920 
16921 	free(tag);
16922 	destroyPQExpBuffer(q);
16923 	destroyPQExpBuffer(delq);
16924 }
16925 
16926 /*
16927  * dumpTableConstraintComment --- dump a constraint's comment if any
16928  *
16929  * This is split out because we need the function in two different places
16930  * depending on whether the constraint is dumped as part of CREATE TABLE
16931  * or as a separate ALTER command.
16932  */
16933 static void
dumpTableConstraintComment(Archive * fout,ConstraintInfo * coninfo)16934 dumpTableConstraintComment(Archive *fout, ConstraintInfo *coninfo)
16935 {
16936 	TableInfo  *tbinfo = coninfo->contable;
16937 	PQExpBuffer conprefix = createPQExpBuffer();
16938 	char	   *qtabname;
16939 
16940 	qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
16941 
16942 	appendPQExpBuffer(conprefix, "CONSTRAINT %s ON",
16943 					  fmtId(coninfo->dobj.name));
16944 
16945 	if (coninfo->dobj.dump & DUMP_COMPONENT_COMMENT)
16946 		dumpComment(fout, conprefix->data, qtabname,
16947 					tbinfo->dobj.namespace->dobj.name,
16948 					tbinfo->rolname,
16949 					coninfo->dobj.catId, 0,
16950 					coninfo->separate ? coninfo->dobj.dumpId : tbinfo->dobj.dumpId);
16951 
16952 	destroyPQExpBuffer(conprefix);
16953 	free(qtabname);
16954 }
16955 
16956 /*
16957  * findLastBuiltinOid_V71 -
16958  *
16959  * find the last built in oid
16960  *
16961  * For 7.1 through 8.0, we do this by retrieving datlastsysoid from the
16962  * pg_database entry for the current database.  (Note: current_database()
16963  * requires 7.3; pg_dump requires 8.0 now.)
16964  */
16965 static Oid
findLastBuiltinOid_V71(Archive * fout)16966 findLastBuiltinOid_V71(Archive *fout)
16967 {
16968 	PGresult   *res;
16969 	Oid			last_oid;
16970 
16971 	res = ExecuteSqlQueryForSingleRow(fout,
16972 									  "SELECT datlastsysoid FROM pg_database WHERE datname = current_database()");
16973 	last_oid = atooid(PQgetvalue(res, 0, PQfnumber(res, "datlastsysoid")));
16974 	PQclear(res);
16975 
16976 	return last_oid;
16977 }
16978 
16979 /*
16980  * dumpSequence
16981  *	  write the declaration (not data) of one user-defined sequence
16982  */
16983 static void
dumpSequence(Archive * fout,TableInfo * tbinfo)16984 dumpSequence(Archive *fout, TableInfo *tbinfo)
16985 {
16986 	DumpOptions *dopt = fout->dopt;
16987 	PGresult   *res;
16988 	char	   *startv,
16989 			   *incby,
16990 			   *maxv,
16991 			   *minv,
16992 			   *cache,
16993 			   *seqtype;
16994 	bool		cycled;
16995 	bool		is_ascending;
16996 	int64		default_minv,
16997 				default_maxv;
16998 	char		bufm[32],
16999 				bufx[32];
17000 	PQExpBuffer query = createPQExpBuffer();
17001 	PQExpBuffer delqry = createPQExpBuffer();
17002 	char	   *qseqname;
17003 
17004 	qseqname = pg_strdup(fmtId(tbinfo->dobj.name));
17005 
17006 	if (fout->remoteVersion >= 100000)
17007 	{
17008 		appendPQExpBuffer(query,
17009 						  "SELECT format_type(seqtypid, NULL), "
17010 						  "seqstart, seqincrement, "
17011 						  "seqmax, seqmin, "
17012 						  "seqcache, seqcycle "
17013 						  "FROM pg_catalog.pg_sequence "
17014 						  "WHERE seqrelid = '%u'::oid",
17015 						  tbinfo->dobj.catId.oid);
17016 	}
17017 	else if (fout->remoteVersion >= 80400)
17018 	{
17019 		/*
17020 		 * Before PostgreSQL 10, sequence metadata is in the sequence itself.
17021 		 *
17022 		 * Note: it might seem that 'bigint' potentially needs to be
17023 		 * schema-qualified, but actually that's a keyword.
17024 		 */
17025 		appendPQExpBuffer(query,
17026 						  "SELECT 'bigint' AS sequence_type, "
17027 						  "start_value, increment_by, max_value, min_value, "
17028 						  "cache_value, is_cycled FROM %s",
17029 						  fmtQualifiedDumpable(tbinfo));
17030 	}
17031 	else
17032 	{
17033 		appendPQExpBuffer(query,
17034 						  "SELECT 'bigint' AS sequence_type, "
17035 						  "0 AS start_value, increment_by, max_value, min_value, "
17036 						  "cache_value, is_cycled FROM %s",
17037 						  fmtQualifiedDumpable(tbinfo));
17038 	}
17039 
17040 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17041 
17042 	if (PQntuples(res) != 1)
17043 	{
17044 		write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
17045 								 "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
17046 								 PQntuples(res)),
17047 				  tbinfo->dobj.name, PQntuples(res));
17048 		exit_nicely(1);
17049 	}
17050 
17051 	seqtype = PQgetvalue(res, 0, 0);
17052 	startv = PQgetvalue(res, 0, 1);
17053 	incby = PQgetvalue(res, 0, 2);
17054 	maxv = PQgetvalue(res, 0, 3);
17055 	minv = PQgetvalue(res, 0, 4);
17056 	cache = PQgetvalue(res, 0, 5);
17057 	cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
17058 
17059 	/* Calculate default limits for a sequence of this type */
17060 	is_ascending = (incby[0] != '-');
17061 	if (strcmp(seqtype, "smallint") == 0)
17062 	{
17063 		default_minv = is_ascending ? 1 : PG_INT16_MIN;
17064 		default_maxv = is_ascending ? PG_INT16_MAX : -1;
17065 	}
17066 	else if (strcmp(seqtype, "integer") == 0)
17067 	{
17068 		default_minv = is_ascending ? 1 : PG_INT32_MIN;
17069 		default_maxv = is_ascending ? PG_INT32_MAX : -1;
17070 	}
17071 	else if (strcmp(seqtype, "bigint") == 0)
17072 	{
17073 		default_minv = is_ascending ? 1 : PG_INT64_MIN;
17074 		default_maxv = is_ascending ? PG_INT64_MAX : -1;
17075 	}
17076 	else
17077 	{
17078 		exit_horribly(NULL, "unrecognized sequence type: %s\n", seqtype);
17079 		default_minv = default_maxv = 0;	/* keep compiler quiet */
17080 	}
17081 
17082 	/*
17083 	 * 64-bit strtol() isn't very portable, so convert the limits to strings
17084 	 * and compare that way.
17085 	 */
17086 	snprintf(bufm, sizeof(bufm), INT64_FORMAT, default_minv);
17087 	snprintf(bufx, sizeof(bufx), INT64_FORMAT, default_maxv);
17088 
17089 	/* Don't print minv/maxv if they match the respective default limit */
17090 	if (strcmp(minv, bufm) == 0)
17091 		minv = NULL;
17092 	if (strcmp(maxv, bufx) == 0)
17093 		maxv = NULL;
17094 
17095 	/*
17096 	 * Identity sequences are not to be dropped separately.
17097 	 */
17098 	if (!tbinfo->is_identity_sequence)
17099 	{
17100 		appendPQExpBuffer(delqry, "DROP SEQUENCE %s;\n",
17101 						  fmtQualifiedDumpable(tbinfo));
17102 	}
17103 
17104 	resetPQExpBuffer(query);
17105 
17106 	if (dopt->binary_upgrade)
17107 	{
17108 		binary_upgrade_set_pg_class_oids(fout, query,
17109 										 tbinfo->dobj.catId.oid, false);
17110 		binary_upgrade_set_type_oids_by_rel_oid(fout, query,
17111 												tbinfo->dobj.catId.oid);
17112 	}
17113 
17114 	if (tbinfo->is_identity_sequence)
17115 	{
17116 		TableInfo  *owning_tab = findTableByOid(tbinfo->owning_tab);
17117 
17118 		appendPQExpBuffer(query,
17119 						  "ALTER TABLE %s ",
17120 						  fmtQualifiedDumpable(owning_tab));
17121 		appendPQExpBuffer(query,
17122 						  "ALTER COLUMN %s ADD GENERATED ",
17123 						  fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
17124 		if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_ALWAYS)
17125 			appendPQExpBuffer(query, "ALWAYS");
17126 		else if (owning_tab->attidentity[tbinfo->owning_col - 1] == ATTRIBUTE_IDENTITY_BY_DEFAULT)
17127 			appendPQExpBuffer(query, "BY DEFAULT");
17128 		appendPQExpBuffer(query, " AS IDENTITY (\n    SEQUENCE NAME %s\n",
17129 						  fmtQualifiedDumpable(tbinfo));
17130 	}
17131 	else
17132 	{
17133 		appendPQExpBuffer(query,
17134 						  "CREATE SEQUENCE %s\n",
17135 						  fmtQualifiedDumpable(tbinfo));
17136 
17137 		if (strcmp(seqtype, "bigint") != 0)
17138 			appendPQExpBuffer(query, "    AS %s\n", seqtype);
17139 	}
17140 
17141 	if (fout->remoteVersion >= 80400)
17142 		appendPQExpBuffer(query, "    START WITH %s\n", startv);
17143 
17144 	appendPQExpBuffer(query, "    INCREMENT BY %s\n", incby);
17145 
17146 	if (minv)
17147 		appendPQExpBuffer(query, "    MINVALUE %s\n", minv);
17148 	else
17149 		appendPQExpBufferStr(query, "    NO MINVALUE\n");
17150 
17151 	if (maxv)
17152 		appendPQExpBuffer(query, "    MAXVALUE %s\n", maxv);
17153 	else
17154 		appendPQExpBufferStr(query, "    NO MAXVALUE\n");
17155 
17156 	appendPQExpBuffer(query,
17157 					  "    CACHE %s%s",
17158 					  cache, (cycled ? "\n    CYCLE" : ""));
17159 
17160 	if (tbinfo->is_identity_sequence)
17161 		appendPQExpBufferStr(query, "\n);\n");
17162 	else
17163 		appendPQExpBufferStr(query, ";\n");
17164 
17165 	/* binary_upgrade:	no need to clear TOAST table oid */
17166 
17167 	if (dopt->binary_upgrade)
17168 		binary_upgrade_extension_member(query, &tbinfo->dobj,
17169 										"SEQUENCE", qseqname,
17170 										tbinfo->dobj.namespace->dobj.name);
17171 
17172 	if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17173 		ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
17174 					 tbinfo->dobj.name,
17175 					 tbinfo->dobj.namespace->dobj.name,
17176 					 NULL,
17177 					 tbinfo->rolname,
17178 					 false, "SEQUENCE", SECTION_PRE_DATA,
17179 					 query->data, delqry->data, NULL,
17180 					 NULL, 0,
17181 					 NULL, NULL);
17182 
17183 	/*
17184 	 * If the sequence is owned by a table column, emit the ALTER for it as a
17185 	 * separate TOC entry immediately following the sequence's own entry. It's
17186 	 * OK to do this rather than using full sorting logic, because the
17187 	 * dependency that tells us it's owned will have forced the table to be
17188 	 * created first.  We can't just include the ALTER in the TOC entry
17189 	 * because it will fail if we haven't reassigned the sequence owner to
17190 	 * match the table's owner.
17191 	 *
17192 	 * We need not schema-qualify the table reference because both sequence
17193 	 * and table must be in the same schema.
17194 	 */
17195 	if (OidIsValid(tbinfo->owning_tab) && !tbinfo->is_identity_sequence)
17196 	{
17197 		TableInfo  *owning_tab = findTableByOid(tbinfo->owning_tab);
17198 
17199 		if (owning_tab == NULL)
17200 			exit_horribly(NULL, "failed sanity check, parent table with OID %u of sequence with OID %u not found\n",
17201 						  tbinfo->owning_tab, tbinfo->dobj.catId.oid);
17202 
17203 		if (owning_tab->dobj.dump & DUMP_COMPONENT_DEFINITION)
17204 		{
17205 			resetPQExpBuffer(query);
17206 			appendPQExpBuffer(query, "ALTER SEQUENCE %s",
17207 							  fmtQualifiedDumpable(tbinfo));
17208 			appendPQExpBuffer(query, " OWNED BY %s",
17209 							  fmtQualifiedDumpable(owning_tab));
17210 			appendPQExpBuffer(query, ".%s;\n",
17211 							  fmtId(owning_tab->attnames[tbinfo->owning_col - 1]));
17212 
17213 			if (tbinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17214 				ArchiveEntry(fout, nilCatalogId, createDumpId(),
17215 							 tbinfo->dobj.name,
17216 							 tbinfo->dobj.namespace->dobj.name,
17217 							 NULL,
17218 							 tbinfo->rolname,
17219 							 false, "SEQUENCE OWNED BY", SECTION_PRE_DATA,
17220 							 query->data, "", NULL,
17221 							 &(tbinfo->dobj.dumpId), 1,
17222 							 NULL, NULL);
17223 		}
17224 	}
17225 
17226 	/* Dump Sequence Comments and Security Labels */
17227 	if (tbinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17228 		dumpComment(fout, "SEQUENCE", qseqname,
17229 					tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
17230 					tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
17231 
17232 	if (tbinfo->dobj.dump & DUMP_COMPONENT_SECLABEL)
17233 		dumpSecLabel(fout, "SEQUENCE", qseqname,
17234 					 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
17235 					 tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
17236 
17237 	PQclear(res);
17238 
17239 	destroyPQExpBuffer(query);
17240 	destroyPQExpBuffer(delqry);
17241 	free(qseqname);
17242 }
17243 
17244 /*
17245  * dumpSequenceData
17246  *	  write the data of one user-defined sequence
17247  */
17248 static void
dumpSequenceData(Archive * fout,TableDataInfo * tdinfo)17249 dumpSequenceData(Archive *fout, TableDataInfo *tdinfo)
17250 {
17251 	TableInfo  *tbinfo = tdinfo->tdtable;
17252 	PGresult   *res;
17253 	char	   *last;
17254 	bool		called;
17255 	PQExpBuffer query = createPQExpBuffer();
17256 
17257 	appendPQExpBuffer(query,
17258 					  "SELECT last_value, is_called FROM %s",
17259 					  fmtQualifiedDumpable(tbinfo));
17260 
17261 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17262 
17263 	if (PQntuples(res) != 1)
17264 	{
17265 		write_msg(NULL, ngettext("query to get data of sequence \"%s\" returned %d row (expected 1)\n",
17266 								 "query to get data of sequence \"%s\" returned %d rows (expected 1)\n",
17267 								 PQntuples(res)),
17268 				  tbinfo->dobj.name, PQntuples(res));
17269 		exit_nicely(1);
17270 	}
17271 
17272 	last = PQgetvalue(res, 0, 0);
17273 	called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0);
17274 
17275 	resetPQExpBuffer(query);
17276 	appendPQExpBufferStr(query, "SELECT pg_catalog.setval(");
17277 	appendStringLiteralAH(query, fmtQualifiedDumpable(tbinfo), fout);
17278 	appendPQExpBuffer(query, ", %s, %s);\n",
17279 					  last, (called ? "true" : "false"));
17280 
17281 	if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
17282 		ArchiveEntry(fout, nilCatalogId, createDumpId(),
17283 					 tbinfo->dobj.name,
17284 					 tbinfo->dobj.namespace->dobj.name,
17285 					 NULL,
17286 					 tbinfo->rolname,
17287 					 false, "SEQUENCE SET", SECTION_DATA,
17288 					 query->data, "", NULL,
17289 					 &(tbinfo->dobj.dumpId), 1,
17290 					 NULL, NULL);
17291 
17292 	PQclear(res);
17293 
17294 	destroyPQExpBuffer(query);
17295 }
17296 
17297 /*
17298  * dumpTrigger
17299  *	  write the declaration of one user-defined table trigger
17300  */
17301 static void
dumpTrigger(Archive * fout,TriggerInfo * tginfo)17302 dumpTrigger(Archive *fout, TriggerInfo *tginfo)
17303 {
17304 	DumpOptions *dopt = fout->dopt;
17305 	TableInfo  *tbinfo = tginfo->tgtable;
17306 	PQExpBuffer query;
17307 	PQExpBuffer delqry;
17308 	PQExpBuffer trigprefix;
17309 	PQExpBuffer trigidentity;
17310 	char	   *qtabname;
17311 	char	   *tgargs;
17312 	size_t		lentgargs;
17313 	const char *p;
17314 	int			findx;
17315 	char	   *tag;
17316 
17317 	/*
17318 	 * we needn't check dobj.dump because TriggerInfo wouldn't have been
17319 	 * created in the first place for non-dumpable triggers
17320 	 */
17321 	if (dopt->dataOnly)
17322 		return;
17323 
17324 	query = createPQExpBuffer();
17325 	delqry = createPQExpBuffer();
17326 	trigprefix = createPQExpBuffer();
17327 	trigidentity = createPQExpBuffer();
17328 
17329 	qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
17330 
17331 	appendPQExpBuffer(trigidentity, "%s ", fmtId(tginfo->dobj.name));
17332 	appendPQExpBuffer(trigidentity, "ON %s", fmtQualifiedDumpable(tbinfo));
17333 
17334 	appendPQExpBuffer(delqry, "DROP TRIGGER %s;\n", trigidentity->data);
17335 
17336 	if (tginfo->tgdef)
17337 	{
17338 		appendPQExpBuffer(query, "%s;\n", tginfo->tgdef);
17339 	}
17340 	else
17341 	{
17342 		if (tginfo->tgisconstraint)
17343 		{
17344 			appendPQExpBufferStr(query, "CREATE CONSTRAINT TRIGGER ");
17345 			appendPQExpBufferStr(query, fmtId(tginfo->tgconstrname));
17346 		}
17347 		else
17348 		{
17349 			appendPQExpBufferStr(query, "CREATE TRIGGER ");
17350 			appendPQExpBufferStr(query, fmtId(tginfo->dobj.name));
17351 		}
17352 		appendPQExpBufferStr(query, "\n    ");
17353 
17354 		/* Trigger type */
17355 		if (TRIGGER_FOR_BEFORE(tginfo->tgtype))
17356 			appendPQExpBufferStr(query, "BEFORE");
17357 		else if (TRIGGER_FOR_AFTER(tginfo->tgtype))
17358 			appendPQExpBufferStr(query, "AFTER");
17359 		else if (TRIGGER_FOR_INSTEAD(tginfo->tgtype))
17360 			appendPQExpBufferStr(query, "INSTEAD OF");
17361 		else
17362 		{
17363 			write_msg(NULL, "unexpected tgtype value: %d\n", tginfo->tgtype);
17364 			exit_nicely(1);
17365 		}
17366 
17367 		findx = 0;
17368 		if (TRIGGER_FOR_INSERT(tginfo->tgtype))
17369 		{
17370 			appendPQExpBufferStr(query, " INSERT");
17371 			findx++;
17372 		}
17373 		if (TRIGGER_FOR_DELETE(tginfo->tgtype))
17374 		{
17375 			if (findx > 0)
17376 				appendPQExpBufferStr(query, " OR DELETE");
17377 			else
17378 				appendPQExpBufferStr(query, " DELETE");
17379 			findx++;
17380 		}
17381 		if (TRIGGER_FOR_UPDATE(tginfo->tgtype))
17382 		{
17383 			if (findx > 0)
17384 				appendPQExpBufferStr(query, " OR UPDATE");
17385 			else
17386 				appendPQExpBufferStr(query, " UPDATE");
17387 			findx++;
17388 		}
17389 		if (TRIGGER_FOR_TRUNCATE(tginfo->tgtype))
17390 		{
17391 			if (findx > 0)
17392 				appendPQExpBufferStr(query, " OR TRUNCATE");
17393 			else
17394 				appendPQExpBufferStr(query, " TRUNCATE");
17395 			findx++;
17396 		}
17397 		appendPQExpBuffer(query, " ON %s\n",
17398 						  fmtQualifiedDumpable(tbinfo));
17399 
17400 		if (tginfo->tgisconstraint)
17401 		{
17402 			if (OidIsValid(tginfo->tgconstrrelid))
17403 			{
17404 				/* regclass output is already quoted */
17405 				appendPQExpBuffer(query, "    FROM %s\n    ",
17406 								  tginfo->tgconstrrelname);
17407 			}
17408 			if (!tginfo->tgdeferrable)
17409 				appendPQExpBufferStr(query, "NOT ");
17410 			appendPQExpBufferStr(query, "DEFERRABLE INITIALLY ");
17411 			if (tginfo->tginitdeferred)
17412 				appendPQExpBufferStr(query, "DEFERRED\n");
17413 			else
17414 				appendPQExpBufferStr(query, "IMMEDIATE\n");
17415 		}
17416 
17417 		if (TRIGGER_FOR_ROW(tginfo->tgtype))
17418 			appendPQExpBufferStr(query, "    FOR EACH ROW\n    ");
17419 		else
17420 			appendPQExpBufferStr(query, "    FOR EACH STATEMENT\n    ");
17421 
17422 		/* regproc output is already sufficiently quoted */
17423 		appendPQExpBuffer(query, "EXECUTE PROCEDURE %s(",
17424 						  tginfo->tgfname);
17425 
17426 		tgargs = (char *) PQunescapeBytea((unsigned char *) tginfo->tgargs,
17427 										  &lentgargs);
17428 		p = tgargs;
17429 		for (findx = 0; findx < tginfo->tgnargs; findx++)
17430 		{
17431 			/* find the embedded null that terminates this trigger argument */
17432 			size_t		tlen = strlen(p);
17433 
17434 			if (p + tlen >= tgargs + lentgargs)
17435 			{
17436 				/* hm, not found before end of bytea value... */
17437 				write_msg(NULL, "invalid argument string (%s) for trigger \"%s\" on table \"%s\"\n",
17438 						  tginfo->tgargs,
17439 						  tginfo->dobj.name,
17440 						  tbinfo->dobj.name);
17441 				exit_nicely(1);
17442 			}
17443 
17444 			if (findx > 0)
17445 				appendPQExpBufferStr(query, ", ");
17446 			appendStringLiteralAH(query, p, fout);
17447 			p += tlen + 1;
17448 		}
17449 		free(tgargs);
17450 		appendPQExpBufferStr(query, ");\n");
17451 	}
17452 
17453 	/* Triggers can depend on extensions */
17454 	append_depends_on_extension(fout, query, &tginfo->dobj,
17455 								"pg_catalog.pg_trigger", "TRIGGER",
17456 								trigidentity->data);
17457 
17458 	if (tginfo->tgisinternal)
17459 	{
17460 		/*
17461 		 * Triggers marked internal only appear here because their 'tgenabled'
17462 		 * flag differs from its parent's.  The trigger is created already, so
17463 		 * remove the CREATE and replace it with an ALTER.  (Clear out the
17464 		 * DROP query too, so that pg_dump --create does not cause errors.)
17465 		 */
17466 		resetPQExpBuffer(query);
17467 		resetPQExpBuffer(delqry);
17468 		appendPQExpBuffer(query, "\nALTER %sTABLE %s ",
17469 						  tbinfo->relkind == RELKIND_FOREIGN_TABLE ? "FOREIGN " : "",
17470 						  fmtQualifiedDumpable(tbinfo));
17471 		switch (tginfo->tgenabled)
17472 		{
17473 			case 'f':
17474 			case 'D':
17475 				appendPQExpBufferStr(query, "DISABLE");
17476 				break;
17477 			case 't':
17478 			case 'O':
17479 				appendPQExpBufferStr(query, "ENABLE");
17480 				break;
17481 			case 'R':
17482 				appendPQExpBufferStr(query, "ENABLE REPLICA");
17483 				break;
17484 			case 'A':
17485 				appendPQExpBufferStr(query, "ENABLE ALWAYS");
17486 				break;
17487 		}
17488 		appendPQExpBuffer(query, " TRIGGER %s;\n",
17489 						  fmtId(tginfo->dobj.name));
17490 	}
17491 	else if (tginfo->tgenabled != 't' && tginfo->tgenabled != 'O')
17492 	{
17493 		appendPQExpBuffer(query, "\nALTER TABLE %s ",
17494 						  fmtQualifiedDumpable(tbinfo));
17495 		switch (tginfo->tgenabled)
17496 		{
17497 			case 'D':
17498 			case 'f':
17499 				appendPQExpBufferStr(query, "DISABLE");
17500 				break;
17501 			case 'A':
17502 				appendPQExpBufferStr(query, "ENABLE ALWAYS");
17503 				break;
17504 			case 'R':
17505 				appendPQExpBufferStr(query, "ENABLE REPLICA");
17506 				break;
17507 			default:
17508 				appendPQExpBufferStr(query, "ENABLE");
17509 				break;
17510 		}
17511 		appendPQExpBuffer(query, " TRIGGER %s;\n",
17512 						  fmtId(tginfo->dobj.name));
17513 	}
17514 
17515 	appendPQExpBuffer(trigprefix, "TRIGGER %s ON",
17516 					  fmtId(tginfo->dobj.name));
17517 
17518 	tag = psprintf("%s %s", tbinfo->dobj.name, tginfo->dobj.name);
17519 
17520 	if (tginfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17521 		ArchiveEntry(fout, tginfo->dobj.catId, tginfo->dobj.dumpId,
17522 					 tag,
17523 					 tbinfo->dobj.namespace->dobj.name,
17524 					 NULL,
17525 					 tbinfo->rolname, false,
17526 					 "TRIGGER", SECTION_POST_DATA,
17527 					 query->data, delqry->data, NULL,
17528 					 NULL, 0,
17529 					 NULL, NULL);
17530 
17531 	if (tginfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17532 		dumpComment(fout, trigprefix->data, qtabname,
17533 					tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
17534 					tginfo->dobj.catId, 0, tginfo->dobj.dumpId);
17535 
17536 	free(tag);
17537 	destroyPQExpBuffer(query);
17538 	destroyPQExpBuffer(delqry);
17539 	destroyPQExpBuffer(trigprefix);
17540 	destroyPQExpBuffer(trigidentity);
17541 	free(qtabname);
17542 }
17543 
17544 /*
17545  * dumpEventTrigger
17546  *	  write the declaration of one user-defined event trigger
17547  */
17548 static void
dumpEventTrigger(Archive * fout,EventTriggerInfo * evtinfo)17549 dumpEventTrigger(Archive *fout, EventTriggerInfo *evtinfo)
17550 {
17551 	DumpOptions *dopt = fout->dopt;
17552 	PQExpBuffer query;
17553 	PQExpBuffer delqry;
17554 	char	   *qevtname;
17555 
17556 	/* Skip if not to be dumped */
17557 	if (!evtinfo->dobj.dump || dopt->dataOnly)
17558 		return;
17559 
17560 	query = createPQExpBuffer();
17561 	delqry = createPQExpBuffer();
17562 
17563 	qevtname = pg_strdup(fmtId(evtinfo->dobj.name));
17564 
17565 	appendPQExpBufferStr(query, "CREATE EVENT TRIGGER ");
17566 	appendPQExpBufferStr(query, qevtname);
17567 	appendPQExpBufferStr(query, " ON ");
17568 	appendPQExpBufferStr(query, fmtId(evtinfo->evtevent));
17569 
17570 	if (strcmp("", evtinfo->evttags) != 0)
17571 	{
17572 		appendPQExpBufferStr(query, "\n         WHEN TAG IN (");
17573 		appendPQExpBufferStr(query, evtinfo->evttags);
17574 		appendPQExpBufferChar(query, ')');
17575 	}
17576 
17577 	appendPQExpBufferStr(query, "\n   EXECUTE PROCEDURE ");
17578 	appendPQExpBufferStr(query, evtinfo->evtfname);
17579 	appendPQExpBufferStr(query, "();\n");
17580 
17581 	if (evtinfo->evtenabled != 'O')
17582 	{
17583 		appendPQExpBuffer(query, "\nALTER EVENT TRIGGER %s ",
17584 						  qevtname);
17585 		switch (evtinfo->evtenabled)
17586 		{
17587 			case 'D':
17588 				appendPQExpBufferStr(query, "DISABLE");
17589 				break;
17590 			case 'A':
17591 				appendPQExpBufferStr(query, "ENABLE ALWAYS");
17592 				break;
17593 			case 'R':
17594 				appendPQExpBufferStr(query, "ENABLE REPLICA");
17595 				break;
17596 			default:
17597 				appendPQExpBufferStr(query, "ENABLE");
17598 				break;
17599 		}
17600 		appendPQExpBufferStr(query, ";\n");
17601 	}
17602 
17603 	appendPQExpBuffer(delqry, "DROP EVENT TRIGGER %s;\n",
17604 					  qevtname);
17605 
17606 	if (dopt->binary_upgrade)
17607 		binary_upgrade_extension_member(query, &evtinfo->dobj,
17608 										"EVENT TRIGGER", qevtname, NULL);
17609 
17610 	if (evtinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17611 		ArchiveEntry(fout, evtinfo->dobj.catId, evtinfo->dobj.dumpId,
17612 					 evtinfo->dobj.name, NULL, NULL,
17613 					 evtinfo->evtowner, false,
17614 					 "EVENT TRIGGER", SECTION_POST_DATA,
17615 					 query->data, delqry->data, NULL,
17616 					 NULL, 0,
17617 					 NULL, NULL);
17618 
17619 	if (evtinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17620 		dumpComment(fout, "EVENT TRIGGER", qevtname,
17621 					NULL, evtinfo->evtowner,
17622 					evtinfo->dobj.catId, 0, evtinfo->dobj.dumpId);
17623 
17624 	destroyPQExpBuffer(query);
17625 	destroyPQExpBuffer(delqry);
17626 	free(qevtname);
17627 }
17628 
17629 /*
17630  * dumpRule
17631  *		Dump a rule
17632  */
17633 static void
dumpRule(Archive * fout,RuleInfo * rinfo)17634 dumpRule(Archive *fout, RuleInfo *rinfo)
17635 {
17636 	DumpOptions *dopt = fout->dopt;
17637 	TableInfo  *tbinfo = rinfo->ruletable;
17638 	bool		is_view;
17639 	PQExpBuffer query;
17640 	PQExpBuffer cmd;
17641 	PQExpBuffer delcmd;
17642 	PQExpBuffer ruleprefix;
17643 	char	   *qtabname;
17644 	PGresult   *res;
17645 	char	   *tag;
17646 
17647 	/* Skip if not to be dumped */
17648 	if (!rinfo->dobj.dump || dopt->dataOnly)
17649 		return;
17650 
17651 	/*
17652 	 * If it is an ON SELECT rule that is created implicitly by CREATE VIEW,
17653 	 * we do not want to dump it as a separate object.
17654 	 */
17655 	if (!rinfo->separate)
17656 		return;
17657 
17658 	/*
17659 	 * If it's an ON SELECT rule, we want to print it as a view definition,
17660 	 * instead of a rule.
17661 	 */
17662 	is_view = (rinfo->ev_type == '1' && rinfo->is_instead);
17663 
17664 	query = createPQExpBuffer();
17665 	cmd = createPQExpBuffer();
17666 	delcmd = createPQExpBuffer();
17667 	ruleprefix = createPQExpBuffer();
17668 
17669 	qtabname = pg_strdup(fmtId(tbinfo->dobj.name));
17670 
17671 	if (is_view)
17672 	{
17673 		PQExpBuffer result;
17674 
17675 		/*
17676 		 * We need OR REPLACE here because we'll be replacing a dummy view.
17677 		 * Otherwise this should look largely like the regular view dump code.
17678 		 */
17679 		appendPQExpBuffer(cmd, "CREATE OR REPLACE VIEW %s",
17680 						  fmtQualifiedDumpable(tbinfo));
17681 		if (nonemptyReloptions(tbinfo->reloptions))
17682 		{
17683 			appendPQExpBufferStr(cmd, " WITH (");
17684 			appendReloptionsArrayAH(cmd, tbinfo->reloptions, "", fout);
17685 			appendPQExpBufferChar(cmd, ')');
17686 		}
17687 		result = createViewAsClause(fout, tbinfo);
17688 		appendPQExpBuffer(cmd, " AS\n%s", result->data);
17689 		destroyPQExpBuffer(result);
17690 		if (tbinfo->checkoption != NULL)
17691 			appendPQExpBuffer(cmd, "\n  WITH %s CHECK OPTION",
17692 							  tbinfo->checkoption);
17693 		appendPQExpBufferStr(cmd, ";\n");
17694 	}
17695 	else
17696 	{
17697 		/* In the rule case, just print pg_get_ruledef's result verbatim */
17698 		appendPQExpBuffer(query,
17699 						  "SELECT pg_catalog.pg_get_ruledef('%u'::pg_catalog.oid)",
17700 						  rinfo->dobj.catId.oid);
17701 
17702 		res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17703 
17704 		if (PQntuples(res) != 1)
17705 		{
17706 			write_msg(NULL, "query to get rule \"%s\" for table \"%s\" failed: wrong number of rows returned\n",
17707 					  rinfo->dobj.name, tbinfo->dobj.name);
17708 			exit_nicely(1);
17709 		}
17710 
17711 		printfPQExpBuffer(cmd, "%s\n", PQgetvalue(res, 0, 0));
17712 
17713 		PQclear(res);
17714 	}
17715 
17716 	/*
17717 	 * Add the command to alter the rules replication firing semantics if it
17718 	 * differs from the default.
17719 	 */
17720 	if (rinfo->ev_enabled != 'O')
17721 	{
17722 		appendPQExpBuffer(cmd, "ALTER TABLE %s ", fmtQualifiedDumpable(tbinfo));
17723 		switch (rinfo->ev_enabled)
17724 		{
17725 			case 'A':
17726 				appendPQExpBuffer(cmd, "ENABLE ALWAYS RULE %s;\n",
17727 								  fmtId(rinfo->dobj.name));
17728 				break;
17729 			case 'R':
17730 				appendPQExpBuffer(cmd, "ENABLE REPLICA RULE %s;\n",
17731 								  fmtId(rinfo->dobj.name));
17732 				break;
17733 			case 'D':
17734 				appendPQExpBuffer(cmd, "DISABLE RULE %s;\n",
17735 								  fmtId(rinfo->dobj.name));
17736 				break;
17737 		}
17738 	}
17739 
17740 	if (is_view)
17741 	{
17742 		/*
17743 		 * We can't DROP a view's ON SELECT rule.  Instead, use CREATE OR
17744 		 * REPLACE VIEW to replace the rule with something with minimal
17745 		 * dependencies.
17746 		 */
17747 		PQExpBuffer result;
17748 
17749 		appendPQExpBuffer(delcmd, "CREATE OR REPLACE VIEW %s",
17750 						  fmtQualifiedDumpable(tbinfo));
17751 		result = createDummyViewAsClause(fout, tbinfo);
17752 		appendPQExpBuffer(delcmd, " AS\n%s;\n", result->data);
17753 		destroyPQExpBuffer(result);
17754 	}
17755 	else
17756 	{
17757 		appendPQExpBuffer(delcmd, "DROP RULE %s ",
17758 						  fmtId(rinfo->dobj.name));
17759 		appendPQExpBuffer(delcmd, "ON %s;\n",
17760 						  fmtQualifiedDumpable(tbinfo));
17761 	}
17762 
17763 	appendPQExpBuffer(ruleprefix, "RULE %s ON",
17764 					  fmtId(rinfo->dobj.name));
17765 
17766 	tag = psprintf("%s %s", tbinfo->dobj.name, rinfo->dobj.name);
17767 
17768 	if (rinfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
17769 		ArchiveEntry(fout, rinfo->dobj.catId, rinfo->dobj.dumpId,
17770 					 tag,
17771 					 tbinfo->dobj.namespace->dobj.name,
17772 					 NULL,
17773 					 tbinfo->rolname, false,
17774 					 "RULE", SECTION_POST_DATA,
17775 					 cmd->data, delcmd->data, NULL,
17776 					 NULL, 0,
17777 					 NULL, NULL);
17778 
17779 	/* Dump rule comments */
17780 	if (rinfo->dobj.dump & DUMP_COMPONENT_COMMENT)
17781 		dumpComment(fout, ruleprefix->data, qtabname,
17782 					tbinfo->dobj.namespace->dobj.name,
17783 					tbinfo->rolname,
17784 					rinfo->dobj.catId, 0, rinfo->dobj.dumpId);
17785 
17786 	free(tag);
17787 	destroyPQExpBuffer(query);
17788 	destroyPQExpBuffer(cmd);
17789 	destroyPQExpBuffer(delcmd);
17790 	destroyPQExpBuffer(ruleprefix);
17791 	free(qtabname);
17792 }
17793 
17794 /*
17795  * getExtensionMembership --- obtain extension membership data
17796  *
17797  * We need to identify objects that are extension members as soon as they're
17798  * loaded, so that we can correctly determine whether they need to be dumped.
17799  * Generally speaking, extension member objects will get marked as *not* to
17800  * be dumped, as they will be recreated by the single CREATE EXTENSION
17801  * command.  However, in binary upgrade mode we still need to dump the members
17802  * individually.
17803  */
17804 void
getExtensionMembership(Archive * fout,ExtensionInfo extinfo[],int numExtensions)17805 getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
17806 					   int numExtensions)
17807 {
17808 	PQExpBuffer query;
17809 	PGresult   *res;
17810 	int			ntups,
17811 				nextmembers,
17812 				i;
17813 	int			i_classid,
17814 				i_objid,
17815 				i_refobjid;
17816 	ExtensionMemberId *extmembers;
17817 	ExtensionInfo *ext;
17818 
17819 	/* Nothing to do if no extensions */
17820 	if (numExtensions == 0)
17821 		return;
17822 
17823 	query = createPQExpBuffer();
17824 
17825 	/* refclassid constraint is redundant but may speed the search */
17826 	appendPQExpBufferStr(query, "SELECT "
17827 						 "classid, objid, refobjid "
17828 						 "FROM pg_depend "
17829 						 "WHERE refclassid = 'pg_extension'::regclass "
17830 						 "AND deptype = 'e' "
17831 						 "ORDER BY 3");
17832 
17833 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
17834 
17835 	ntups = PQntuples(res);
17836 
17837 	i_classid = PQfnumber(res, "classid");
17838 	i_objid = PQfnumber(res, "objid");
17839 	i_refobjid = PQfnumber(res, "refobjid");
17840 
17841 	extmembers = (ExtensionMemberId *) pg_malloc(ntups * sizeof(ExtensionMemberId));
17842 	nextmembers = 0;
17843 
17844 	/*
17845 	 * Accumulate data into extmembers[].
17846 	 *
17847 	 * Since we ordered the SELECT by referenced ID, we can expect that
17848 	 * multiple entries for the same extension will appear together; this
17849 	 * saves on searches.
17850 	 */
17851 	ext = NULL;
17852 
17853 	for (i = 0; i < ntups; i++)
17854 	{
17855 		CatalogId	objId;
17856 		Oid			extId;
17857 
17858 		objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
17859 		objId.oid = atooid(PQgetvalue(res, i, i_objid));
17860 		extId = atooid(PQgetvalue(res, i, i_refobjid));
17861 
17862 		if (ext == NULL ||
17863 			ext->dobj.catId.oid != extId)
17864 			ext = findExtensionByOid(extId);
17865 
17866 		if (ext == NULL)
17867 		{
17868 			/* shouldn't happen */
17869 			fprintf(stderr, "could not find referenced extension %u\n", extId);
17870 			continue;
17871 		}
17872 
17873 		extmembers[nextmembers].catId = objId;
17874 		extmembers[nextmembers].ext = ext;
17875 		nextmembers++;
17876 	}
17877 
17878 	PQclear(res);
17879 
17880 	/* Remember the data for use later */
17881 	setExtensionMembership(extmembers, nextmembers);
17882 
17883 	destroyPQExpBuffer(query);
17884 }
17885 
17886 /*
17887  * processExtensionTables --- deal with extension configuration tables
17888  *
17889  * There are two parts to this process:
17890  *
17891  * 1. Identify and create dump records for extension configuration tables.
17892  *
17893  *	  Extensions can mark tables as "configuration", which means that the user
17894  *	  is able and expected to modify those tables after the extension has been
17895  *	  loaded.  For these tables, we dump out only the data- the structure is
17896  *	  expected to be handled at CREATE EXTENSION time, including any indexes or
17897  *	  foreign keys, which brings us to-
17898  *
17899  * 2. Record FK dependencies between configuration tables.
17900  *
17901  *	  Due to the FKs being created at CREATE EXTENSION time and therefore before
17902  *	  the data is loaded, we have to work out what the best order for reloading
17903  *	  the data is, to avoid FK violations when the tables are restored.  This is
17904  *	  not perfect- we can't handle circular dependencies and if any exist they
17905  *	  will cause an invalid dump to be produced (though at least all of the data
17906  *	  is included for a user to manually restore).  This is currently documented
17907  *	  but perhaps we can provide a better solution in the future.
17908  */
17909 void
processExtensionTables(Archive * fout,ExtensionInfo extinfo[],int numExtensions)17910 processExtensionTables(Archive *fout, ExtensionInfo extinfo[],
17911 					   int numExtensions)
17912 {
17913 	DumpOptions *dopt = fout->dopt;
17914 	PQExpBuffer query;
17915 	PGresult   *res;
17916 	int			ntups,
17917 				i;
17918 	int			i_conrelid,
17919 				i_confrelid;
17920 
17921 	/* Nothing to do if no extensions */
17922 	if (numExtensions == 0)
17923 		return;
17924 
17925 	/*
17926 	 * Identify extension configuration tables and create TableDataInfo
17927 	 * objects for them, ensuring their data will be dumped even though the
17928 	 * tables themselves won't be.
17929 	 *
17930 	 * Note that we create TableDataInfo objects even in schemaOnly mode, ie,
17931 	 * user data in a configuration table is treated like schema data. This
17932 	 * seems appropriate since system data in a config table would get
17933 	 * reloaded by CREATE EXTENSION.
17934 	 */
17935 	for (i = 0; i < numExtensions; i++)
17936 	{
17937 		ExtensionInfo *curext = &(extinfo[i]);
17938 		char	   *extconfig = curext->extconfig;
17939 		char	   *extcondition = curext->extcondition;
17940 		char	  **extconfigarray = NULL;
17941 		char	  **extconditionarray = NULL;
17942 		int			nconfigitems;
17943 		int			nconditionitems;
17944 
17945 		if (parsePGArray(extconfig, &extconfigarray, &nconfigitems) &&
17946 			parsePGArray(extcondition, &extconditionarray, &nconditionitems) &&
17947 			nconfigitems == nconditionitems)
17948 		{
17949 			int			j;
17950 
17951 			for (j = 0; j < nconfigitems; j++)
17952 			{
17953 				TableInfo  *configtbl;
17954 				Oid			configtbloid = atooid(extconfigarray[j]);
17955 				bool		dumpobj =
17956 				curext->dobj.dump & DUMP_COMPONENT_DEFINITION;
17957 
17958 				configtbl = findTableByOid(configtbloid);
17959 				if (configtbl == NULL)
17960 					continue;
17961 
17962 				/*
17963 				 * Tables of not-to-be-dumped extensions shouldn't be dumped
17964 				 * unless the table or its schema is explicitly included
17965 				 */
17966 				if (!(curext->dobj.dump & DUMP_COMPONENT_DEFINITION))
17967 				{
17968 					/* check table explicitly requested */
17969 					if (table_include_oids.head != NULL &&
17970 						simple_oid_list_member(&table_include_oids,
17971 											   configtbloid))
17972 						dumpobj = true;
17973 
17974 					/* check table's schema explicitly requested */
17975 					if (configtbl->dobj.namespace->dobj.dump &
17976 						DUMP_COMPONENT_DATA)
17977 						dumpobj = true;
17978 				}
17979 
17980 				/* check table excluded by an exclusion switch */
17981 				if (table_exclude_oids.head != NULL &&
17982 					simple_oid_list_member(&table_exclude_oids,
17983 										   configtbloid))
17984 					dumpobj = false;
17985 
17986 				/* check schema excluded by an exclusion switch */
17987 				if (simple_oid_list_member(&schema_exclude_oids,
17988 										   configtbl->dobj.namespace->dobj.catId.oid))
17989 					dumpobj = false;
17990 
17991 				if (dumpobj)
17992 				{
17993 					/*
17994 					 * Note: config tables are dumped without OIDs regardless
17995 					 * of the --oids setting.  This is because row filtering
17996 					 * conditions aren't compatible with dumping OIDs.
17997 					 */
17998 					makeTableDataInfo(dopt, configtbl, false);
17999 					if (configtbl->dataObj != NULL)
18000 					{
18001 						if (strlen(extconditionarray[j]) > 0)
18002 							configtbl->dataObj->filtercond = pg_strdup(extconditionarray[j]);
18003 					}
18004 				}
18005 			}
18006 		}
18007 		if (extconfigarray)
18008 			free(extconfigarray);
18009 		if (extconditionarray)
18010 			free(extconditionarray);
18011 	}
18012 
18013 	/*
18014 	 * Now that all the TableInfoData objects have been created for all the
18015 	 * extensions, check their FK dependencies and register them to try and
18016 	 * dump the data out in an order that they can be restored in.
18017 	 *
18018 	 * Note that this is not a problem for user tables as their FKs are
18019 	 * recreated after the data has been loaded.
18020 	 */
18021 
18022 	query = createPQExpBuffer();
18023 
18024 	printfPQExpBuffer(query,
18025 					  "SELECT conrelid, confrelid "
18026 					  "FROM pg_constraint "
18027 					  "JOIN pg_depend ON (objid = confrelid) "
18028 					  "WHERE contype = 'f' "
18029 					  "AND refclassid = 'pg_extension'::regclass "
18030 					  "AND classid = 'pg_class'::regclass;");
18031 
18032 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
18033 	ntups = PQntuples(res);
18034 
18035 	i_conrelid = PQfnumber(res, "conrelid");
18036 	i_confrelid = PQfnumber(res, "confrelid");
18037 
18038 	/* Now get the dependencies and register them */
18039 	for (i = 0; i < ntups; i++)
18040 	{
18041 		Oid			conrelid,
18042 					confrelid;
18043 		TableInfo  *reftable,
18044 				   *contable;
18045 
18046 		conrelid = atooid(PQgetvalue(res, i, i_conrelid));
18047 		confrelid = atooid(PQgetvalue(res, i, i_confrelid));
18048 		contable = findTableByOid(conrelid);
18049 		reftable = findTableByOid(confrelid);
18050 
18051 		if (reftable == NULL ||
18052 			reftable->dataObj == NULL ||
18053 			contable == NULL ||
18054 			contable->dataObj == NULL)
18055 			continue;
18056 
18057 		/*
18058 		 * Make referencing TABLE_DATA object depend on the referenced table's
18059 		 * TABLE_DATA object.
18060 		 */
18061 		addObjectDependency(&contable->dataObj->dobj,
18062 							reftable->dataObj->dobj.dumpId);
18063 	}
18064 	PQclear(res);
18065 	destroyPQExpBuffer(query);
18066 }
18067 
18068 /*
18069  * getDependencies --- obtain available dependency data
18070  */
18071 static void
getDependencies(Archive * fout)18072 getDependencies(Archive *fout)
18073 {
18074 	PQExpBuffer query;
18075 	PGresult   *res;
18076 	int			ntups,
18077 				i;
18078 	int			i_classid,
18079 				i_objid,
18080 				i_refclassid,
18081 				i_refobjid,
18082 				i_deptype;
18083 	DumpableObject *dobj,
18084 			   *refdobj;
18085 
18086 	if (g_verbose)
18087 		write_msg(NULL, "reading dependency data\n");
18088 
18089 	query = createPQExpBuffer();
18090 
18091 	/*
18092 	 * Messy query to collect the dependency data we need.  Note that we
18093 	 * ignore the sub-object column, so that dependencies of or on a column
18094 	 * look the same as dependencies of or on a whole table.
18095 	 *
18096 	 * PIN dependencies aren't interesting, and EXTENSION dependencies were
18097 	 * already processed by getExtensionMembership.
18098 	 */
18099 	appendPQExpBufferStr(query, "SELECT "
18100 						 "classid, objid, refclassid, refobjid, deptype "
18101 						 "FROM pg_depend "
18102 						 "WHERE deptype != 'p' AND deptype != 'e'\n");
18103 
18104 	/*
18105 	 * Since we don't treat pg_amop entries as separate DumpableObjects, we
18106 	 * have to translate their dependencies into dependencies of their parent
18107 	 * opfamily.  Ignore internal dependencies though, as those will point to
18108 	 * their parent opclass, which we needn't consider here (and if we did,
18109 	 * it'd just result in circular dependencies).  Also, "loose" opfamily
18110 	 * entries will have dependencies on their parent opfamily, which we
18111 	 * should drop since they'd likewise become useless self-dependencies.
18112 	 * (But be sure to keep deps on *other* opfamilies; see amopsortfamily.)
18113 	 *
18114 	 * Skip this for pre-8.3 source servers: pg_opfamily doesn't exist there,
18115 	 * and the (known) cases where it would matter to have these dependencies
18116 	 * can't arise anyway.
18117 	 */
18118 	if (fout->remoteVersion >= 80300)
18119 	{
18120 		appendPQExpBufferStr(query, "UNION ALL\n"
18121 							 "SELECT 'pg_opfamily'::regclass AS classid, amopfamily AS objid, refclassid, refobjid, deptype "
18122 							 "FROM pg_depend d, pg_amop o "
18123 							 "WHERE deptype NOT IN ('p', 'e', 'i') AND "
18124 							 "classid = 'pg_amop'::regclass AND objid = o.oid "
18125 							 "AND NOT (refclassid = 'pg_opfamily'::regclass AND amopfamily = refobjid)\n");
18126 
18127 		/* Likewise for pg_amproc entries */
18128 		appendPQExpBufferStr(query, "UNION ALL\n"
18129 							 "SELECT 'pg_opfamily'::regclass AS classid, amprocfamily AS objid, refclassid, refobjid, deptype "
18130 							 "FROM pg_depend d, pg_amproc p "
18131 							 "WHERE deptype NOT IN ('p', 'e', 'i') AND "
18132 							 "classid = 'pg_amproc'::regclass AND objid = p.oid "
18133 							 "AND NOT (refclassid = 'pg_opfamily'::regclass AND amprocfamily = refobjid)\n");
18134 	}
18135 
18136 	/* Sort the output for efficiency below */
18137 	appendPQExpBufferStr(query, "ORDER BY 1,2");
18138 
18139 	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
18140 
18141 	ntups = PQntuples(res);
18142 
18143 	i_classid = PQfnumber(res, "classid");
18144 	i_objid = PQfnumber(res, "objid");
18145 	i_refclassid = PQfnumber(res, "refclassid");
18146 	i_refobjid = PQfnumber(res, "refobjid");
18147 	i_deptype = PQfnumber(res, "deptype");
18148 
18149 	/*
18150 	 * Since we ordered the SELECT by referencing ID, we can expect that
18151 	 * multiple entries for the same object will appear together; this saves
18152 	 * on searches.
18153 	 */
18154 	dobj = NULL;
18155 
18156 	for (i = 0; i < ntups; i++)
18157 	{
18158 		CatalogId	objId;
18159 		CatalogId	refobjId;
18160 		char		deptype;
18161 
18162 		objId.tableoid = atooid(PQgetvalue(res, i, i_classid));
18163 		objId.oid = atooid(PQgetvalue(res, i, i_objid));
18164 		refobjId.tableoid = atooid(PQgetvalue(res, i, i_refclassid));
18165 		refobjId.oid = atooid(PQgetvalue(res, i, i_refobjid));
18166 		deptype = *(PQgetvalue(res, i, i_deptype));
18167 
18168 		if (dobj == NULL ||
18169 			dobj->catId.tableoid != objId.tableoid ||
18170 			dobj->catId.oid != objId.oid)
18171 			dobj = findObjectByCatalogId(objId);
18172 
18173 		/*
18174 		 * Failure to find objects mentioned in pg_depend is not unexpected,
18175 		 * since for example we don't collect info about TOAST tables.
18176 		 */
18177 		if (dobj == NULL)
18178 		{
18179 #ifdef NOT_USED
18180 			fprintf(stderr, "no referencing object %u %u\n",
18181 					objId.tableoid, objId.oid);
18182 #endif
18183 			continue;
18184 		}
18185 
18186 		refdobj = findObjectByCatalogId(refobjId);
18187 
18188 		if (refdobj == NULL)
18189 		{
18190 #ifdef NOT_USED
18191 			fprintf(stderr, "no referenced object %u %u\n",
18192 					refobjId.tableoid, refobjId.oid);
18193 #endif
18194 			continue;
18195 		}
18196 
18197 		/*
18198 		 * For 'x' dependencies, mark the object for later; we still add the
18199 		 * normal dependency, for possible ordering purposes.  Currently
18200 		 * pg_dump_sort.c knows to put extensions ahead of all object types
18201 		 * that could possibly depend on them, but this is safer.
18202 		 */
18203 		if (deptype == 'x')
18204 			dobj->depends_on_ext = true;
18205 
18206 		/*
18207 		 * Ordinarily, table rowtypes have implicit dependencies on their
18208 		 * tables.  However, for a composite type the implicit dependency goes
18209 		 * the other way in pg_depend; which is the right thing for DROP but
18210 		 * it doesn't produce the dependency ordering we need. So in that one
18211 		 * case, we reverse the direction of the dependency.
18212 		 */
18213 		if (deptype == 'i' &&
18214 			dobj->objType == DO_TABLE &&
18215 			refdobj->objType == DO_TYPE)
18216 			addObjectDependency(refdobj, dobj->dumpId);
18217 		else
18218 			/* normal case */
18219 			addObjectDependency(dobj, refdobj->dumpId);
18220 	}
18221 
18222 	PQclear(res);
18223 
18224 	destroyPQExpBuffer(query);
18225 }
18226 
18227 
18228 /*
18229  * createBoundaryObjects - create dummy DumpableObjects to represent
18230  * dump section boundaries.
18231  */
18232 static DumpableObject *
createBoundaryObjects(void)18233 createBoundaryObjects(void)
18234 {
18235 	DumpableObject *dobjs;
18236 
18237 	dobjs = (DumpableObject *) pg_malloc(2 * sizeof(DumpableObject));
18238 
18239 	dobjs[0].objType = DO_PRE_DATA_BOUNDARY;
18240 	dobjs[0].catId = nilCatalogId;
18241 	AssignDumpId(dobjs + 0);
18242 	dobjs[0].name = pg_strdup("PRE-DATA BOUNDARY");
18243 
18244 	dobjs[1].objType = DO_POST_DATA_BOUNDARY;
18245 	dobjs[1].catId = nilCatalogId;
18246 	AssignDumpId(dobjs + 1);
18247 	dobjs[1].name = pg_strdup("POST-DATA BOUNDARY");
18248 
18249 	return dobjs;
18250 }
18251 
18252 /*
18253  * addBoundaryDependencies - add dependencies as needed to enforce the dump
18254  * section boundaries.
18255  */
18256 static void
addBoundaryDependencies(DumpableObject ** dobjs,int numObjs,DumpableObject * boundaryObjs)18257 addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
18258 						DumpableObject *boundaryObjs)
18259 {
18260 	DumpableObject *preDataBound = boundaryObjs + 0;
18261 	DumpableObject *postDataBound = boundaryObjs + 1;
18262 	int			i;
18263 
18264 	for (i = 0; i < numObjs; i++)
18265 	{
18266 		DumpableObject *dobj = dobjs[i];
18267 
18268 		/*
18269 		 * The classification of object types here must match the SECTION_xxx
18270 		 * values assigned during subsequent ArchiveEntry calls!
18271 		 */
18272 		switch (dobj->objType)
18273 		{
18274 			case DO_NAMESPACE:
18275 			case DO_EXTENSION:
18276 			case DO_TYPE:
18277 			case DO_SHELL_TYPE:
18278 			case DO_FUNC:
18279 			case DO_AGG:
18280 			case DO_OPERATOR:
18281 			case DO_ACCESS_METHOD:
18282 			case DO_OPCLASS:
18283 			case DO_OPFAMILY:
18284 			case DO_COLLATION:
18285 			case DO_CONVERSION:
18286 			case DO_TABLE:
18287 			case DO_ATTRDEF:
18288 			case DO_PROCLANG:
18289 			case DO_CAST:
18290 			case DO_DUMMY_TYPE:
18291 			case DO_TSPARSER:
18292 			case DO_TSDICT:
18293 			case DO_TSTEMPLATE:
18294 			case DO_TSCONFIG:
18295 			case DO_FDW:
18296 			case DO_FOREIGN_SERVER:
18297 			case DO_TRANSFORM:
18298 			case DO_BLOB:
18299 				/* Pre-data objects: must come before the pre-data boundary */
18300 				addObjectDependency(preDataBound, dobj->dumpId);
18301 				break;
18302 			case DO_TABLE_DATA:
18303 			case DO_SEQUENCE_SET:
18304 			case DO_BLOB_DATA:
18305 				/* Data objects: must come between the boundaries */
18306 				addObjectDependency(dobj, preDataBound->dumpId);
18307 				addObjectDependency(postDataBound, dobj->dumpId);
18308 				break;
18309 			case DO_INDEX:
18310 			case DO_INDEX_ATTACH:
18311 			case DO_STATSEXT:
18312 			case DO_REFRESH_MATVIEW:
18313 			case DO_TRIGGER:
18314 			case DO_EVENT_TRIGGER:
18315 			case DO_DEFAULT_ACL:
18316 			case DO_POLICY:
18317 			case DO_PUBLICATION:
18318 			case DO_PUBLICATION_REL:
18319 			case DO_SUBSCRIPTION:
18320 				/* Post-data objects: must come after the post-data boundary */
18321 				addObjectDependency(dobj, postDataBound->dumpId);
18322 				break;
18323 			case DO_RULE:
18324 				/* Rules are post-data, but only if dumped separately */
18325 				if (((RuleInfo *) dobj)->separate)
18326 					addObjectDependency(dobj, postDataBound->dumpId);
18327 				break;
18328 			case DO_CONSTRAINT:
18329 			case DO_FK_CONSTRAINT:
18330 				/* Constraints are post-data, but only if dumped separately */
18331 				if (((ConstraintInfo *) dobj)->separate)
18332 					addObjectDependency(dobj, postDataBound->dumpId);
18333 				break;
18334 			case DO_PRE_DATA_BOUNDARY:
18335 				/* nothing to do */
18336 				break;
18337 			case DO_POST_DATA_BOUNDARY:
18338 				/* must come after the pre-data boundary */
18339 				addObjectDependency(dobj, preDataBound->dumpId);
18340 				break;
18341 		}
18342 	}
18343 }
18344 
18345 
18346 /*
18347  * BuildArchiveDependencies - create dependency data for archive TOC entries
18348  *
18349  * The raw dependency data obtained by getDependencies() is not terribly
18350  * useful in an archive dump, because in many cases there are dependency
18351  * chains linking through objects that don't appear explicitly in the dump.
18352  * For example, a view will depend on its _RETURN rule while the _RETURN rule
18353  * will depend on other objects --- but the rule will not appear as a separate
18354  * object in the dump.  We need to adjust the view's dependencies to include
18355  * whatever the rule depends on that is included in the dump.
18356  *
18357  * Just to make things more complicated, there are also "special" dependencies
18358  * such as the dependency of a TABLE DATA item on its TABLE, which we must
18359  * not rearrange because pg_restore knows that TABLE DATA only depends on
18360  * its table.  In these cases we must leave the dependencies strictly as-is
18361  * even if they refer to not-to-be-dumped objects.
18362  *
18363  * To handle this, the convention is that "special" dependencies are created
18364  * during ArchiveEntry calls, and an archive TOC item that has any such
18365  * entries will not be touched here.  Otherwise, we recursively search the
18366  * DumpableObject data structures to build the correct dependencies for each
18367  * archive TOC item.
18368  */
18369 static void
BuildArchiveDependencies(Archive * fout)18370 BuildArchiveDependencies(Archive *fout)
18371 {
18372 	ArchiveHandle *AH = (ArchiveHandle *) fout;
18373 	TocEntry   *te;
18374 
18375 	/* Scan all TOC entries in the archive */
18376 	for (te = AH->toc->next; te != AH->toc; te = te->next)
18377 	{
18378 		DumpableObject *dobj;
18379 		DumpId	   *dependencies;
18380 		int			nDeps;
18381 		int			allocDeps;
18382 
18383 		/* No need to process entries that will not be dumped */
18384 		if (te->reqs == 0)
18385 			continue;
18386 		/* Ignore entries that already have "special" dependencies */
18387 		if (te->nDeps > 0)
18388 			continue;
18389 		/* Otherwise, look up the item's original DumpableObject, if any */
18390 		dobj = findObjectByDumpId(te->dumpId);
18391 		if (dobj == NULL)
18392 			continue;
18393 		/* No work if it has no dependencies */
18394 		if (dobj->nDeps <= 0)
18395 			continue;
18396 		/* Set up work array */
18397 		allocDeps = 64;
18398 		dependencies = (DumpId *) pg_malloc(allocDeps * sizeof(DumpId));
18399 		nDeps = 0;
18400 		/* Recursively find all dumpable dependencies */
18401 		findDumpableDependencies(AH, dobj,
18402 								 &dependencies, &nDeps, &allocDeps);
18403 		/* And save 'em ... */
18404 		if (nDeps > 0)
18405 		{
18406 			dependencies = (DumpId *) pg_realloc(dependencies,
18407 												 nDeps * sizeof(DumpId));
18408 			te->dependencies = dependencies;
18409 			te->nDeps = nDeps;
18410 		}
18411 		else
18412 			free(dependencies);
18413 	}
18414 }
18415 
18416 /* Recursive search subroutine for BuildArchiveDependencies */
18417 static void
findDumpableDependencies(ArchiveHandle * AH,DumpableObject * dobj,DumpId ** dependencies,int * nDeps,int * allocDeps)18418 findDumpableDependencies(ArchiveHandle *AH, DumpableObject *dobj,
18419 						 DumpId **dependencies, int *nDeps, int *allocDeps)
18420 {
18421 	int			i;
18422 
18423 	/*
18424 	 * Ignore section boundary objects: if we search through them, we'll
18425 	 * report lots of bogus dependencies.
18426 	 */
18427 	if (dobj->objType == DO_PRE_DATA_BOUNDARY ||
18428 		dobj->objType == DO_POST_DATA_BOUNDARY)
18429 		return;
18430 
18431 	for (i = 0; i < dobj->nDeps; i++)
18432 	{
18433 		DumpId		depid = dobj->dependencies[i];
18434 
18435 		if (TocIDRequired(AH, depid) != 0)
18436 		{
18437 			/* Object will be dumped, so just reference it as a dependency */
18438 			if (*nDeps >= *allocDeps)
18439 			{
18440 				*allocDeps *= 2;
18441 				*dependencies = (DumpId *) pg_realloc(*dependencies,
18442 													  *allocDeps * sizeof(DumpId));
18443 			}
18444 			(*dependencies)[*nDeps] = depid;
18445 			(*nDeps)++;
18446 		}
18447 		else
18448 		{
18449 			/*
18450 			 * Object will not be dumped, so recursively consider its deps. We
18451 			 * rely on the assumption that sortDumpableObjects already broke
18452 			 * any dependency loops, else we might recurse infinitely.
18453 			 */
18454 			DumpableObject *otherdobj = findObjectByDumpId(depid);
18455 
18456 			if (otherdobj)
18457 				findDumpableDependencies(AH, otherdobj,
18458 										 dependencies, nDeps, allocDeps);
18459 		}
18460 	}
18461 }
18462 
18463 
18464 /*
18465  * getFormattedTypeName - retrieve a nicely-formatted type name for the
18466  * given type OID.
18467  *
18468  * This does not guarantee to schema-qualify the output, so it should not
18469  * be used to create the target object name for CREATE or ALTER commands.
18470  *
18471  * Note that the result is cached and must not be freed by the caller.
18472  */
18473 static const char *
getFormattedTypeName(Archive * fout,Oid oid,OidOptions opts)18474 getFormattedTypeName(Archive *fout, Oid oid, OidOptions opts)
18475 {
18476 	TypeInfo   *typeInfo;
18477 	char	   *result;
18478 	PQExpBuffer query;
18479 	PGresult   *res;
18480 
18481 	if (oid == 0)
18482 	{
18483 		if ((opts & zeroAsOpaque) != 0)
18484 			return g_opaque_type;
18485 		else if ((opts & zeroAsAny) != 0)
18486 			return "'any'";
18487 		else if ((opts & zeroAsStar) != 0)
18488 			return "*";
18489 		else if ((opts & zeroAsNone) != 0)
18490 			return "NONE";
18491 	}
18492 
18493 	/* see if we have the result cached in the type's TypeInfo record */
18494 	typeInfo = findTypeByOid(oid);
18495 	if (typeInfo && typeInfo->ftypname)
18496 		return typeInfo->ftypname;
18497 
18498 	query = createPQExpBuffer();
18499 	appendPQExpBuffer(query, "SELECT pg_catalog.format_type('%u'::pg_catalog.oid, NULL)",
18500 					  oid);
18501 
18502 	res = ExecuteSqlQueryForSingleRow(fout, query->data);
18503 
18504 	/* result of format_type is already quoted */
18505 	result = pg_strdup(PQgetvalue(res, 0, 0));
18506 
18507 	PQclear(res);
18508 	destroyPQExpBuffer(query);
18509 
18510 	/*
18511 	 * Cache the result for re-use in later requests, if possible.  If we
18512 	 * don't have a TypeInfo for the type, the string will be leaked once the
18513 	 * caller is done with it ... but that case really should not happen, so
18514 	 * leaking if it does seems acceptable.
18515 	 */
18516 	if (typeInfo)
18517 		typeInfo->ftypname = result;
18518 
18519 	return result;
18520 }
18521 
18522 /*
18523  * Return a column list clause for the given relation.
18524  *
18525  * Special case: if there are no undropped columns in the relation, return
18526  * "", not an invalid "()" column list.
18527  */
18528 static const char *
fmtCopyColumnList(const TableInfo * ti,PQExpBuffer buffer)18529 fmtCopyColumnList(const TableInfo *ti, PQExpBuffer buffer)
18530 {
18531 	int			numatts = ti->numatts;
18532 	char	  **attnames = ti->attnames;
18533 	bool	   *attisdropped = ti->attisdropped;
18534 	bool		needComma;
18535 	int			i;
18536 
18537 	appendPQExpBufferChar(buffer, '(');
18538 	needComma = false;
18539 	for (i = 0; i < numatts; i++)
18540 	{
18541 		if (attisdropped[i])
18542 			continue;
18543 		if (needComma)
18544 			appendPQExpBufferStr(buffer, ", ");
18545 		appendPQExpBufferStr(buffer, fmtId(attnames[i]));
18546 		needComma = true;
18547 	}
18548 
18549 	if (!needComma)
18550 		return "";				/* no undropped columns */
18551 
18552 	appendPQExpBufferChar(buffer, ')');
18553 	return buffer->data;
18554 }
18555 
18556 /*
18557  * Check if a reloptions array is nonempty.
18558  */
18559 static bool
nonemptyReloptions(const char * reloptions)18560 nonemptyReloptions(const char *reloptions)
18561 {
18562 	/* Don't want to print it if it's just "{}" */
18563 	return (reloptions != NULL && strlen(reloptions) > 2);
18564 }
18565 
18566 /*
18567  * Format a reloptions array and append it to the given buffer.
18568  *
18569  * "prefix" is prepended to the option names; typically it's "" or "toast.".
18570  */
18571 static void
appendReloptionsArrayAH(PQExpBuffer buffer,const char * reloptions,const char * prefix,Archive * fout)18572 appendReloptionsArrayAH(PQExpBuffer buffer, const char *reloptions,
18573 						const char *prefix, Archive *fout)
18574 {
18575 	bool		res;
18576 
18577 	res = appendReloptionsArray(buffer, reloptions, prefix, fout->encoding,
18578 								fout->std_strings);
18579 	if (!res)
18580 		write_msg(NULL, "WARNING: could not parse reloptions array\n");
18581 }
18582