1 /*-------------------------------------------------------------------------
2  *
3  * objectaddress.c
4  *	  functions for working with ObjectAddresses
5  *
6  * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *	  src/backend/catalog/objectaddress.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 
16 #include "postgres.h"
17 
18 #include "access/htup_details.h"
19 #include "access/sysattr.h"
20 #include "catalog/catalog.h"
21 #include "catalog/indexing.h"
22 #include "catalog/objectaddress.h"
23 #include "catalog/pg_am.h"
24 #include "catalog/pg_amop.h"
25 #include "catalog/pg_amproc.h"
26 #include "catalog/pg_attrdef.h"
27 #include "catalog/pg_authid.h"
28 #include "catalog/pg_cast.h"
29 #include "catalog/pg_default_acl.h"
30 #include "catalog/pg_event_trigger.h"
31 #include "catalog/pg_collation.h"
32 #include "catalog/pg_constraint.h"
33 #include "catalog/pg_conversion.h"
34 #include "catalog/pg_database.h"
35 #include "catalog/pg_extension.h"
36 #include "catalog/pg_foreign_data_wrapper.h"
37 #include "catalog/pg_foreign_server.h"
38 #include "catalog/pg_language.h"
39 #include "catalog/pg_largeobject.h"
40 #include "catalog/pg_largeobject_metadata.h"
41 #include "catalog/pg_namespace.h"
42 #include "catalog/pg_opclass.h"
43 #include "catalog/pg_opfamily.h"
44 #include "catalog/pg_operator.h"
45 #include "catalog/pg_proc.h"
46 #include "catalog/pg_policy.h"
47 #include "catalog/pg_publication.h"
48 #include "catalog/pg_publication_rel.h"
49 #include "catalog/pg_rewrite.h"
50 #include "catalog/pg_statistic_ext.h"
51 #include "catalog/pg_subscription.h"
52 #include "catalog/pg_tablespace.h"
53 #include "catalog/pg_transform.h"
54 #include "catalog/pg_trigger.h"
55 #include "catalog/pg_ts_config.h"
56 #include "catalog/pg_ts_dict.h"
57 #include "catalog/pg_ts_parser.h"
58 #include "catalog/pg_ts_template.h"
59 #include "catalog/pg_type.h"
60 #include "catalog/pg_user_mapping.h"
61 #include "commands/dbcommands.h"
62 #include "commands/defrem.h"
63 #include "commands/event_trigger.h"
64 #include "commands/extension.h"
65 #include "commands/policy.h"
66 #include "commands/proclang.h"
67 #include "commands/tablespace.h"
68 #include "commands/trigger.h"
69 #include "foreign/foreign.h"
70 #include "funcapi.h"
71 #include "miscadmin.h"
72 #include "nodes/makefuncs.h"
73 #include "parser/parse_func.h"
74 #include "parser/parse_oper.h"
75 #include "parser/parse_type.h"
76 #include "rewrite/rewriteSupport.h"
77 #include "storage/large_object.h"
78 #include "storage/lmgr.h"
79 #include "storage/sinval.h"
80 #include "utils/builtins.h"
81 #include "utils/fmgroids.h"
82 #include "utils/lsyscache.h"
83 #include "utils/memutils.h"
84 #include "utils/regproc.h"
85 #include "utils/syscache.h"
86 #include "utils/tqual.h"
87 
88 /*
89  * ObjectProperty
90  *
91  * This array provides a common part of system object structure; to help
92  * consolidate routines to handle various kind of object classes.
93  */
94 typedef struct
95 {
96 	Oid			class_oid;		/* oid of catalog */
97 	Oid			oid_index_oid;	/* oid of index on system oid column */
98 	int			oid_catcache_id;	/* id of catcache on system oid column	*/
99 	int			name_catcache_id;	/* id of catcache on (name,namespace), or
100 									 * (name) if the object does not live in a
101 									 * namespace */
102 	AttrNumber	attnum_name;	/* attnum of name field */
103 	AttrNumber	attnum_namespace;	/* attnum of namespace field */
104 	AttrNumber	attnum_owner;	/* attnum of owner field */
105 	AttrNumber	attnum_acl;		/* attnum of acl field */
106 	ObjectType	objtype;		/* OBJECT_* of this object type */
107 	bool		is_nsp_name_unique; /* can the nsp/name combination (or name
108 									 * alone, if there's no namespace) be
109 									 * considered a unique identifier for an
110 									 * object of this class? */
111 } ObjectPropertyType;
112 
113 static const ObjectPropertyType ObjectProperty[] =
114 {
115 	{
116 		AccessMethodRelationId,
117 		AmOidIndexId,
118 		AMOID,
119 		AMNAME,
120 		Anum_pg_am_amname,
121 		InvalidAttrNumber,
122 		InvalidAttrNumber,
123 		InvalidAttrNumber,
124 		-1,
125 		true
126 	},
127 	{
128 		CastRelationId,
129 		CastOidIndexId,
130 		-1,
131 		-1,
132 		InvalidAttrNumber,
133 		InvalidAttrNumber,
134 		InvalidAttrNumber,
135 		InvalidAttrNumber,
136 		-1,
137 		false
138 	},
139 	{
140 		CollationRelationId,
141 		CollationOidIndexId,
142 		COLLOID,
143 		-1,						/* COLLNAMEENCNSP also takes encoding */
144 		Anum_pg_collation_collname,
145 		Anum_pg_collation_collnamespace,
146 		Anum_pg_collation_collowner,
147 		InvalidAttrNumber,
148 		OBJECT_COLLATION,
149 		true
150 	},
151 	{
152 		ConstraintRelationId,
153 		ConstraintOidIndexId,
154 		CONSTROID,
155 		-1,
156 		Anum_pg_constraint_conname,
157 		Anum_pg_constraint_connamespace,
158 		InvalidAttrNumber,
159 		InvalidAttrNumber,
160 		-1,
161 		false
162 	},
163 	{
164 		ConversionRelationId,
165 		ConversionOidIndexId,
166 		CONVOID,
167 		CONNAMENSP,
168 		Anum_pg_conversion_conname,
169 		Anum_pg_conversion_connamespace,
170 		Anum_pg_conversion_conowner,
171 		InvalidAttrNumber,
172 		OBJECT_CONVERSION,
173 		true
174 	},
175 	{
176 		DatabaseRelationId,
177 		DatabaseOidIndexId,
178 		DATABASEOID,
179 		-1,
180 		Anum_pg_database_datname,
181 		InvalidAttrNumber,
182 		Anum_pg_database_datdba,
183 		Anum_pg_database_datacl,
184 		OBJECT_DATABASE,
185 		true
186 	},
187 	{
188 		ExtensionRelationId,
189 		ExtensionOidIndexId,
190 		-1,
191 		-1,
192 		Anum_pg_extension_extname,
193 		InvalidAttrNumber,		/* extension doesn't belong to extnamespace */
194 		Anum_pg_extension_extowner,
195 		InvalidAttrNumber,
196 		OBJECT_EXTENSION,
197 		true
198 	},
199 	{
200 		ForeignDataWrapperRelationId,
201 		ForeignDataWrapperOidIndexId,
202 		FOREIGNDATAWRAPPEROID,
203 		FOREIGNDATAWRAPPERNAME,
204 		Anum_pg_foreign_data_wrapper_fdwname,
205 		InvalidAttrNumber,
206 		Anum_pg_foreign_data_wrapper_fdwowner,
207 		Anum_pg_foreign_data_wrapper_fdwacl,
208 		OBJECT_FDW,
209 		true
210 	},
211 	{
212 		ForeignServerRelationId,
213 		ForeignServerOidIndexId,
214 		FOREIGNSERVEROID,
215 		FOREIGNSERVERNAME,
216 		Anum_pg_foreign_server_srvname,
217 		InvalidAttrNumber,
218 		Anum_pg_foreign_server_srvowner,
219 		Anum_pg_foreign_server_srvacl,
220 		OBJECT_FOREIGN_SERVER,
221 		true
222 	},
223 	{
224 		ProcedureRelationId,
225 		ProcedureOidIndexId,
226 		PROCOID,
227 		-1,						/* PROCNAMEARGSNSP also takes argument types */
228 		Anum_pg_proc_proname,
229 		Anum_pg_proc_pronamespace,
230 		Anum_pg_proc_proowner,
231 		Anum_pg_proc_proacl,
232 		OBJECT_FUNCTION,
233 		false
234 	},
235 	{
236 		LanguageRelationId,
237 		LanguageOidIndexId,
238 		LANGOID,
239 		LANGNAME,
240 		Anum_pg_language_lanname,
241 		InvalidAttrNumber,
242 		Anum_pg_language_lanowner,
243 		Anum_pg_language_lanacl,
244 		OBJECT_LANGUAGE,
245 		true
246 	},
247 	{
248 		LargeObjectMetadataRelationId,
249 		LargeObjectMetadataOidIndexId,
250 		-1,
251 		-1,
252 		InvalidAttrNumber,
253 		InvalidAttrNumber,
254 		Anum_pg_largeobject_metadata_lomowner,
255 		Anum_pg_largeobject_metadata_lomacl,
256 		OBJECT_LARGEOBJECT,
257 		false
258 	},
259 	{
260 		OperatorClassRelationId,
261 		OpclassOidIndexId,
262 		CLAOID,
263 		-1,						/* CLAAMNAMENSP also takes opcmethod */
264 		Anum_pg_opclass_opcname,
265 		Anum_pg_opclass_opcnamespace,
266 		Anum_pg_opclass_opcowner,
267 		InvalidAttrNumber,
268 		OBJECT_OPCLASS,
269 		true
270 	},
271 	{
272 		OperatorRelationId,
273 		OperatorOidIndexId,
274 		OPEROID,
275 		-1,						/* OPERNAMENSP also takes left and right type */
276 		Anum_pg_operator_oprname,
277 		Anum_pg_operator_oprnamespace,
278 		Anum_pg_operator_oprowner,
279 		InvalidAttrNumber,
280 		OBJECT_OPERATOR,
281 		false
282 	},
283 	{
284 		OperatorFamilyRelationId,
285 		OpfamilyOidIndexId,
286 		OPFAMILYOID,
287 		-1,						/* OPFAMILYAMNAMENSP also takes opfmethod */
288 		Anum_pg_opfamily_opfname,
289 		Anum_pg_opfamily_opfnamespace,
290 		Anum_pg_opfamily_opfowner,
291 		InvalidAttrNumber,
292 		OBJECT_OPFAMILY,
293 		true
294 	},
295 	{
296 		AuthIdRelationId,
297 		AuthIdOidIndexId,
298 		AUTHOID,
299 		AUTHNAME,
300 		Anum_pg_authid_rolname,
301 		InvalidAttrNumber,
302 		InvalidAttrNumber,
303 		InvalidAttrNumber,
304 		-1,
305 		true
306 	},
307 	{
308 		RewriteRelationId,
309 		RewriteOidIndexId,
310 		-1,
311 		-1,
312 		Anum_pg_rewrite_rulename,
313 		InvalidAttrNumber,
314 		InvalidAttrNumber,
315 		InvalidAttrNumber,
316 		-1,
317 		false
318 	},
319 	{
320 		NamespaceRelationId,
321 		NamespaceOidIndexId,
322 		NAMESPACEOID,
323 		NAMESPACENAME,
324 		Anum_pg_namespace_nspname,
325 		InvalidAttrNumber,
326 		Anum_pg_namespace_nspowner,
327 		Anum_pg_namespace_nspacl,
328 		OBJECT_SCHEMA,
329 		true
330 	},
331 	{
332 		RelationRelationId,
333 		ClassOidIndexId,
334 		RELOID,
335 		RELNAMENSP,
336 		Anum_pg_class_relname,
337 		Anum_pg_class_relnamespace,
338 		Anum_pg_class_relowner,
339 		Anum_pg_class_relacl,
340 		OBJECT_TABLE,
341 		true
342 	},
343 	{
344 		TableSpaceRelationId,
345 		TablespaceOidIndexId,
346 		TABLESPACEOID,
347 		-1,
348 		Anum_pg_tablespace_spcname,
349 		InvalidAttrNumber,
350 		Anum_pg_tablespace_spcowner,
351 		Anum_pg_tablespace_spcacl,
352 		OBJECT_TABLESPACE,
353 		true
354 	},
355 	{
356 		TransformRelationId,
357 		TransformOidIndexId,
358 		TRFOID,
359 		InvalidAttrNumber
360 	},
361 	{
362 		TriggerRelationId,
363 		TriggerOidIndexId,
364 		-1,
365 		-1,
366 		Anum_pg_trigger_tgname,
367 		InvalidAttrNumber,
368 		InvalidAttrNumber,
369 		InvalidAttrNumber,
370 		-1,
371 		false
372 	},
373 	{
374 		PolicyRelationId,
375 		PolicyOidIndexId,
376 		-1,
377 		-1,
378 		Anum_pg_policy_polname,
379 		InvalidAttrNumber,
380 		InvalidAttrNumber,
381 		InvalidAttrNumber,
382 		-1,
383 		false
384 	},
385 	{
386 		EventTriggerRelationId,
387 		EventTriggerOidIndexId,
388 		EVENTTRIGGEROID,
389 		EVENTTRIGGERNAME,
390 		Anum_pg_event_trigger_evtname,
391 		InvalidAttrNumber,
392 		Anum_pg_event_trigger_evtowner,
393 		InvalidAttrNumber,
394 		OBJECT_EVENT_TRIGGER,
395 		true
396 	},
397 	{
398 		TSConfigRelationId,
399 		TSConfigOidIndexId,
400 		TSCONFIGOID,
401 		TSCONFIGNAMENSP,
402 		Anum_pg_ts_config_cfgname,
403 		Anum_pg_ts_config_cfgnamespace,
404 		Anum_pg_ts_config_cfgowner,
405 		InvalidAttrNumber,
406 		OBJECT_TSCONFIGURATION,
407 		true
408 	},
409 	{
410 		TSDictionaryRelationId,
411 		TSDictionaryOidIndexId,
412 		TSDICTOID,
413 		TSDICTNAMENSP,
414 		Anum_pg_ts_dict_dictname,
415 		Anum_pg_ts_dict_dictnamespace,
416 		Anum_pg_ts_dict_dictowner,
417 		InvalidAttrNumber,
418 		OBJECT_TSDICTIONARY,
419 		true
420 	},
421 	{
422 		TSParserRelationId,
423 		TSParserOidIndexId,
424 		TSPARSEROID,
425 		TSPARSERNAMENSP,
426 		Anum_pg_ts_parser_prsname,
427 		Anum_pg_ts_parser_prsnamespace,
428 		InvalidAttrNumber,
429 		InvalidAttrNumber,
430 		-1,
431 		true
432 	},
433 	{
434 		TSTemplateRelationId,
435 		TSTemplateOidIndexId,
436 		TSTEMPLATEOID,
437 		TSTEMPLATENAMENSP,
438 		Anum_pg_ts_template_tmplname,
439 		Anum_pg_ts_template_tmplnamespace,
440 		InvalidAttrNumber,
441 		InvalidAttrNumber,
442 		-1,
443 		true,
444 	},
445 	{
446 		TypeRelationId,
447 		TypeOidIndexId,
448 		TYPEOID,
449 		TYPENAMENSP,
450 		Anum_pg_type_typname,
451 		Anum_pg_type_typnamespace,
452 		Anum_pg_type_typowner,
453 		Anum_pg_type_typacl,
454 		OBJECT_TYPE,
455 		true
456 	},
457 	{
458 		PublicationRelationId,
459 		PublicationObjectIndexId,
460 		PUBLICATIONOID,
461 		PUBLICATIONNAME,
462 		Anum_pg_publication_pubname,
463 		InvalidAttrNumber,
464 		Anum_pg_publication_pubowner,
465 		InvalidAttrNumber,
466 		OBJECT_PUBLICATION,
467 		true
468 	},
469 	{
470 		SubscriptionRelationId,
471 		SubscriptionObjectIndexId,
472 		SUBSCRIPTIONOID,
473 		SUBSCRIPTIONNAME,
474 		Anum_pg_subscription_subname,
475 		InvalidAttrNumber,
476 		Anum_pg_subscription_subowner,
477 		InvalidAttrNumber,
478 		OBJECT_SUBSCRIPTION,
479 		true
480 	},
481 	{
482 		StatisticExtRelationId,
483 		StatisticExtOidIndexId,
484 		STATEXTOID,
485 		STATEXTNAMENSP,
486 		Anum_pg_statistic_ext_stxname,
487 		Anum_pg_statistic_ext_stxnamespace,
488 		Anum_pg_statistic_ext_stxowner,
489 		InvalidAttrNumber,		/* no ACL (same as relation) */
490 		OBJECT_STATISTIC_EXT,
491 		true
492 	}
493 };
494 
495 /*
496  * This struct maps the string object types as returned by
497  * getObjectTypeDescription into ObjType enum values.  Note that some enum
498  * values can be obtained by different names, and that some string object types
499  * do not have corresponding values in the output enum.  The user of this map
500  * must be careful to test for invalid values being returned.
501  *
502  * To ease maintenance, this follows the order of getObjectTypeDescription.
503  */
504 static const struct object_type_map
505 {
506 	const char *tm_name;
507 	ObjectType	tm_type;
508 }
509 
510 			ObjectTypeMap[] =
511 {
512 	/* OCLASS_CLASS, all kinds of relations */
513 	{
514 		"table", OBJECT_TABLE
515 	},
516 	{
517 		"index", OBJECT_INDEX
518 	},
519 	{
520 		"sequence", OBJECT_SEQUENCE
521 	},
522 	{
523 		"toast table", -1
524 	},							/* unmapped */
525 	{
526 		"view", OBJECT_VIEW
527 	},
528 	{
529 		"materialized view", OBJECT_MATVIEW
530 	},
531 	{
532 		"composite type", -1
533 	},							/* unmapped */
534 	{
535 		"foreign table", OBJECT_FOREIGN_TABLE
536 	},
537 	{
538 		"table column", OBJECT_COLUMN
539 	},
540 	{
541 		"index column", -1
542 	},							/* unmapped */
543 	{
544 		"sequence column", -1
545 	},							/* unmapped */
546 	{
547 		"toast table column", -1
548 	},							/* unmapped */
549 	{
550 		"view column", -1
551 	},							/* unmapped */
552 	{
553 		"materialized view column", -1
554 	},							/* unmapped */
555 	{
556 		"composite type column", -1
557 	},							/* unmapped */
558 	{
559 		"foreign table column", OBJECT_COLUMN
560 	},
561 	/* OCLASS_PROC */
562 	{
563 		"aggregate", OBJECT_AGGREGATE
564 	},
565 	{
566 		"function", OBJECT_FUNCTION
567 	},
568 	{
569 		"procedure", OBJECT_PROCEDURE
570 	},
571 	/* OCLASS_TYPE */
572 	{
573 		"type", OBJECT_TYPE
574 	},
575 	/* OCLASS_CAST */
576 	{
577 		"cast", OBJECT_CAST
578 	},
579 	/* OCLASS_COLLATION */
580 	{
581 		"collation", OBJECT_COLLATION
582 	},
583 	/* OCLASS_CONSTRAINT */
584 	{
585 		"table constraint", OBJECT_TABCONSTRAINT
586 	},
587 	{
588 		"domain constraint", OBJECT_DOMCONSTRAINT
589 	},
590 	/* OCLASS_CONVERSION */
591 	{
592 		"conversion", OBJECT_CONVERSION
593 	},
594 	/* OCLASS_DEFAULT */
595 	{
596 		"default value", OBJECT_DEFAULT
597 	},
598 	/* OCLASS_LANGUAGE */
599 	{
600 		"language", OBJECT_LANGUAGE
601 	},
602 	/* OCLASS_LARGEOBJECT */
603 	{
604 		"large object", OBJECT_LARGEOBJECT
605 	},
606 	/* OCLASS_OPERATOR */
607 	{
608 		"operator", OBJECT_OPERATOR
609 	},
610 	/* OCLASS_OPCLASS */
611 	{
612 		"operator class", OBJECT_OPCLASS
613 	},
614 	/* OCLASS_OPFAMILY */
615 	{
616 		"operator family", OBJECT_OPFAMILY
617 	},
618 	/* OCLASS_AM */
619 	{
620 		"access method", OBJECT_ACCESS_METHOD
621 	},
622 	/* OCLASS_AMOP */
623 	{
624 		"operator of access method", OBJECT_AMOP
625 	},
626 	/* OCLASS_AMPROC */
627 	{
628 		"function of access method", OBJECT_AMPROC
629 	},
630 	/* OCLASS_REWRITE */
631 	{
632 		"rule", OBJECT_RULE
633 	},
634 	/* OCLASS_TRIGGER */
635 	{
636 		"trigger", OBJECT_TRIGGER
637 	},
638 	/* OCLASS_SCHEMA */
639 	{
640 		"schema", OBJECT_SCHEMA
641 	},
642 	/* OCLASS_TSPARSER */
643 	{
644 		"text search parser", OBJECT_TSPARSER
645 	},
646 	/* OCLASS_TSDICT */
647 	{
648 		"text search dictionary", OBJECT_TSDICTIONARY
649 	},
650 	/* OCLASS_TSTEMPLATE */
651 	{
652 		"text search template", OBJECT_TSTEMPLATE
653 	},
654 	/* OCLASS_TSCONFIG */
655 	{
656 		"text search configuration", OBJECT_TSCONFIGURATION
657 	},
658 	/* OCLASS_ROLE */
659 	{
660 		"role", OBJECT_ROLE
661 	},
662 	/* OCLASS_DATABASE */
663 	{
664 		"database", OBJECT_DATABASE
665 	},
666 	/* OCLASS_TBLSPACE */
667 	{
668 		"tablespace", OBJECT_TABLESPACE
669 	},
670 	/* OCLASS_FDW */
671 	{
672 		"foreign-data wrapper", OBJECT_FDW
673 	},
674 	/* OCLASS_FOREIGN_SERVER */
675 	{
676 		"server", OBJECT_FOREIGN_SERVER
677 	},
678 	/* OCLASS_USER_MAPPING */
679 	{
680 		"user mapping", OBJECT_USER_MAPPING
681 	},
682 	/* OCLASS_DEFACL */
683 	{
684 		"default acl", OBJECT_DEFACL
685 	},
686 	/* OCLASS_EXTENSION */
687 	{
688 		"extension", OBJECT_EXTENSION
689 	},
690 	/* OCLASS_EVENT_TRIGGER */
691 	{
692 		"event trigger", OBJECT_EVENT_TRIGGER
693 	},
694 	/* OCLASS_POLICY */
695 	{
696 		"policy", OBJECT_POLICY
697 	},
698 	/* OCLASS_PUBLICATION */
699 	{
700 		"publication", OBJECT_PUBLICATION
701 	},
702 	/* OCLASS_PUBLICATION_REL */
703 	{
704 		"publication relation", OBJECT_PUBLICATION_REL
705 	},
706 	/* OCLASS_SUBSCRIPTION */
707 	{
708 		"subscription", OBJECT_SUBSCRIPTION
709 	},
710 	/* OCLASS_TRANSFORM */
711 	{
712 		"transform", OBJECT_TRANSFORM
713 	},
714 	/* OCLASS_STATISTIC_EXT */
715 	{
716 		"statistics object", OBJECT_STATISTIC_EXT
717 	}
718 };
719 
720 const ObjectAddress InvalidObjectAddress =
721 {
722 	InvalidOid,
723 	InvalidOid,
724 	0
725 };
726 
727 static ObjectAddress get_object_address_unqualified(ObjectType objtype,
728 							   Value *strval, bool missing_ok);
729 static ObjectAddress get_relation_by_qualified_name(ObjectType objtype,
730 							   List *object, Relation *relp,
731 							   LOCKMODE lockmode, bool missing_ok);
732 static ObjectAddress get_object_address_relobject(ObjectType objtype,
733 							 List *object, Relation *relp, bool missing_ok);
734 static ObjectAddress get_object_address_attribute(ObjectType objtype,
735 							 List *object, Relation *relp,
736 							 LOCKMODE lockmode, bool missing_ok);
737 static ObjectAddress get_object_address_attrdef(ObjectType objtype,
738 						   List *object, Relation *relp, LOCKMODE lockmode,
739 						   bool missing_ok);
740 static ObjectAddress get_object_address_type(ObjectType objtype,
741 						TypeName *typename, bool missing_ok);
742 static ObjectAddress get_object_address_opcf(ObjectType objtype, List *object,
743 						bool missing_ok);
744 static ObjectAddress get_object_address_opf_member(ObjectType objtype,
745 							  List *object, bool missing_ok);
746 
747 static ObjectAddress get_object_address_usermapping(List *object,
748 							   bool missing_ok);
749 static ObjectAddress get_object_address_publication_rel(List *object,
750 								   Relation *relp,
751 								   bool missing_ok);
752 static ObjectAddress get_object_address_defacl(List *object,
753 						  bool missing_ok);
754 static const ObjectPropertyType *get_object_property_data(Oid class_id);
755 
756 static void getRelationDescription(StringInfo buffer, Oid relid);
757 static void getOpFamilyDescription(StringInfo buffer, Oid opfid);
758 static void getRelationTypeDescription(StringInfo buffer, Oid relid,
759 						   int32 objectSubId);
760 static void getProcedureTypeDescription(StringInfo buffer, Oid procid);
761 static void getConstraintTypeDescription(StringInfo buffer, Oid constroid);
762 static void getOpFamilyIdentity(StringInfo buffer, Oid opfid, List **object);
763 static void getRelationIdentity(StringInfo buffer, Oid relid, List **object);
764 
765 /*
766  * Translate an object name and arguments (as passed by the parser) to an
767  * ObjectAddress.
768  *
769  * The returned object will be locked using the specified lockmode.  If a
770  * sub-object is looked up, the parent object will be locked instead.
771  *
772  * If the object is a relation or a child object of a relation (e.g. an
773  * attribute or constraint), the relation is also opened and *relp receives
774  * the open relcache entry pointer; otherwise, *relp is set to NULL.  This
775  * is a bit grotty but it makes life simpler, since the caller will
776  * typically need the relcache entry too.  Caller must close the relcache
777  * entry when done with it.  The relation is locked with the specified lockmode
778  * if the target object is the relation itself or an attribute, but for other
779  * child objects, only AccessShareLock is acquired on the relation.
780  *
781  * If the object is not found, an error is thrown, unless missing_ok is
782  * true.  In this case, no lock is acquired, relp is set to NULL, and the
783  * returned address has objectId set to InvalidOid.
784  *
785  * We don't currently provide a function to release the locks acquired here;
786  * typically, the lock must be held until commit to guard against a concurrent
787  * drop operation.
788  *
789  * Note: If the object is not found, we don't give any indication of the
790  * reason.  (It might have been a missing schema if the name was qualified, or
791  * a nonexistent type name in case of a cast, function or operator; etc).
792  * Currently there is only one caller that might be interested in such info, so
793  * we don't spend much effort here.  If more callers start to care, it might be
794  * better to add some support for that in this function.
795  */
796 ObjectAddress
797 get_object_address(ObjectType objtype, Node *object,
798 				   Relation *relp, LOCKMODE lockmode, bool missing_ok)
799 {
800 	ObjectAddress address;
801 	ObjectAddress old_address = {InvalidOid, InvalidOid, 0};
802 	Relation	relation = NULL;
803 	uint64		inval_count;
804 
805 	/* Some kind of lock must be taken. */
806 	Assert(lockmode != NoLock);
807 
808 	for (;;)
809 	{
810 		/*
811 		 * Remember this value, so that, after looking up the object name and
812 		 * locking it, we can check whether any invalidation messages have
813 		 * been processed that might require a do-over.
814 		 */
815 		inval_count = SharedInvalidMessageCounter;
816 
817 		/* Look up object address. */
818 		switch (objtype)
819 		{
820 			case OBJECT_INDEX:
821 			case OBJECT_SEQUENCE:
822 			case OBJECT_TABLE:
823 			case OBJECT_VIEW:
824 			case OBJECT_MATVIEW:
825 			case OBJECT_FOREIGN_TABLE:
826 				address =
827 					get_relation_by_qualified_name(objtype, castNode(List, object),
828 												   &relation, lockmode,
829 												   missing_ok);
830 				break;
831 			case OBJECT_COLUMN:
832 				address =
833 					get_object_address_attribute(objtype, castNode(List, object),
834 												 &relation, lockmode,
835 												 missing_ok);
836 				break;
837 			case OBJECT_DEFAULT:
838 				address =
839 					get_object_address_attrdef(objtype, castNode(List, object),
840 											   &relation, lockmode,
841 											   missing_ok);
842 				break;
843 			case OBJECT_RULE:
844 			case OBJECT_TRIGGER:
845 			case OBJECT_TABCONSTRAINT:
846 			case OBJECT_POLICY:
847 				address = get_object_address_relobject(objtype, castNode(List, object),
848 													   &relation, missing_ok);
849 				break;
850 			case OBJECT_DOMCONSTRAINT:
851 				{
852 					List	   *objlist;
853 					ObjectAddress domaddr;
854 					char	   *constrname;
855 
856 					objlist = castNode(List, object);
857 					domaddr = get_object_address_type(OBJECT_DOMAIN,
858 													  linitial_node(TypeName, objlist),
859 													  missing_ok);
860 					constrname = strVal(lsecond(objlist));
861 
862 					address.classId = ConstraintRelationId;
863 					address.objectId = get_domain_constraint_oid(domaddr.objectId,
864 																 constrname, missing_ok);
865 					address.objectSubId = 0;
866 
867 				}
868 				break;
869 			case OBJECT_DATABASE:
870 			case OBJECT_EXTENSION:
871 			case OBJECT_TABLESPACE:
872 			case OBJECT_ROLE:
873 			case OBJECT_SCHEMA:
874 			case OBJECT_LANGUAGE:
875 			case OBJECT_FDW:
876 			case OBJECT_FOREIGN_SERVER:
877 			case OBJECT_EVENT_TRIGGER:
878 			case OBJECT_ACCESS_METHOD:
879 			case OBJECT_PUBLICATION:
880 			case OBJECT_SUBSCRIPTION:
881 				address = get_object_address_unqualified(objtype,
882 														 (Value *) object, missing_ok);
883 				break;
884 			case OBJECT_TYPE:
885 			case OBJECT_DOMAIN:
886 				address = get_object_address_type(objtype, castNode(TypeName, object), missing_ok);
887 				break;
888 			case OBJECT_AGGREGATE:
889 			case OBJECT_FUNCTION:
890 			case OBJECT_PROCEDURE:
891 			case OBJECT_ROUTINE:
892 				address.classId = ProcedureRelationId;
893 				address.objectId = LookupFuncWithArgs(objtype, castNode(ObjectWithArgs, object), missing_ok);
894 				address.objectSubId = 0;
895 				break;
896 			case OBJECT_OPERATOR:
897 				address.classId = OperatorRelationId;
898 				address.objectId = LookupOperWithArgs(castNode(ObjectWithArgs, object), missing_ok);
899 				address.objectSubId = 0;
900 				break;
901 			case OBJECT_COLLATION:
902 				address.classId = CollationRelationId;
903 				address.objectId = get_collation_oid(castNode(List, object), missing_ok);
904 				address.objectSubId = 0;
905 				break;
906 			case OBJECT_CONVERSION:
907 				address.classId = ConversionRelationId;
908 				address.objectId = get_conversion_oid(castNode(List, object), missing_ok);
909 				address.objectSubId = 0;
910 				break;
911 			case OBJECT_OPCLASS:
912 			case OBJECT_OPFAMILY:
913 				address = get_object_address_opcf(objtype, castNode(List, object), missing_ok);
914 				break;
915 			case OBJECT_AMOP:
916 			case OBJECT_AMPROC:
917 				address = get_object_address_opf_member(objtype, castNode(List, object), missing_ok);
918 				break;
919 			case OBJECT_LARGEOBJECT:
920 				address.classId = LargeObjectRelationId;
921 				address.objectId = oidparse(object);
922 				address.objectSubId = 0;
923 				if (!LargeObjectExists(address.objectId))
924 				{
925 					if (!missing_ok)
926 						ereport(ERROR,
927 								(errcode(ERRCODE_UNDEFINED_OBJECT),
928 								 errmsg("large object %u does not exist",
929 										address.objectId)));
930 				}
931 				break;
932 			case OBJECT_CAST:
933 				{
934 					TypeName   *sourcetype = linitial_node(TypeName, castNode(List, object));
935 					TypeName   *targettype = lsecond_node(TypeName, castNode(List, object));
936 					Oid			sourcetypeid;
937 					Oid			targettypeid;
938 
939 					sourcetypeid = LookupTypeNameOid(NULL, sourcetype, missing_ok);
940 					targettypeid = LookupTypeNameOid(NULL, targettype, missing_ok);
941 					address.classId = CastRelationId;
942 					address.objectId =
943 						get_cast_oid(sourcetypeid, targettypeid, missing_ok);
944 					address.objectSubId = 0;
945 				}
946 				break;
947 			case OBJECT_TRANSFORM:
948 				{
949 					TypeName   *typename = linitial_node(TypeName, castNode(List, object));
950 					char	   *langname = strVal(lsecond(castNode(List, object)));
951 					Oid			type_id = LookupTypeNameOid(NULL, typename, missing_ok);
952 					Oid			lang_id = get_language_oid(langname, missing_ok);
953 
954 					address.classId = TransformRelationId;
955 					address.objectId =
956 						get_transform_oid(type_id, lang_id, missing_ok);
957 					address.objectSubId = 0;
958 				}
959 				break;
960 			case OBJECT_TSPARSER:
961 				address.classId = TSParserRelationId;
962 				address.objectId = get_ts_parser_oid(castNode(List, object), missing_ok);
963 				address.objectSubId = 0;
964 				break;
965 			case OBJECT_TSDICTIONARY:
966 				address.classId = TSDictionaryRelationId;
967 				address.objectId = get_ts_dict_oid(castNode(List, object), missing_ok);
968 				address.objectSubId = 0;
969 				break;
970 			case OBJECT_TSTEMPLATE:
971 				address.classId = TSTemplateRelationId;
972 				address.objectId = get_ts_template_oid(castNode(List, object), missing_ok);
973 				address.objectSubId = 0;
974 				break;
975 			case OBJECT_TSCONFIGURATION:
976 				address.classId = TSConfigRelationId;
977 				address.objectId = get_ts_config_oid(castNode(List, object), missing_ok);
978 				address.objectSubId = 0;
979 				break;
980 			case OBJECT_USER_MAPPING:
981 				address = get_object_address_usermapping(castNode(List, object),
982 														 missing_ok);
983 				break;
984 			case OBJECT_PUBLICATION_REL:
985 				address = get_object_address_publication_rel(castNode(List, object),
986 															 &relation,
987 															 missing_ok);
988 				break;
989 			case OBJECT_DEFACL:
990 				address = get_object_address_defacl(castNode(List, object),
991 													missing_ok);
992 				break;
993 			case OBJECT_STATISTIC_EXT:
994 				address.classId = StatisticExtRelationId;
995 				address.objectId = get_statistics_object_oid(castNode(List, object),
996 															 missing_ok);
997 				address.objectSubId = 0;
998 				break;
999 			default:
1000 				elog(ERROR, "unrecognized objtype: %d", (int) objtype);
1001 				/* placate compiler, in case it thinks elog might return */
1002 				address.classId = InvalidOid;
1003 				address.objectId = InvalidOid;
1004 				address.objectSubId = 0;
1005 		}
1006 
1007 		/*
1008 		 * If we could not find the supplied object, return without locking.
1009 		 */
1010 		if (!OidIsValid(address.objectId))
1011 		{
1012 			Assert(missing_ok);
1013 			return address;
1014 		}
1015 
1016 		/*
1017 		 * If we're retrying, see if we got the same answer as last time.  If
1018 		 * so, we're done; if not, we locked the wrong thing, so give up our
1019 		 * lock.
1020 		 */
1021 		if (OidIsValid(old_address.classId))
1022 		{
1023 			if (old_address.classId == address.classId
1024 				&& old_address.objectId == address.objectId
1025 				&& old_address.objectSubId == address.objectSubId)
1026 				break;
1027 			if (old_address.classId != RelationRelationId)
1028 			{
1029 				if (IsSharedRelation(old_address.classId))
1030 					UnlockSharedObject(old_address.classId,
1031 									   old_address.objectId,
1032 									   0, lockmode);
1033 				else
1034 					UnlockDatabaseObject(old_address.classId,
1035 										 old_address.objectId,
1036 										 0, lockmode);
1037 			}
1038 		}
1039 
1040 		/*
1041 		 * If we're dealing with a relation or attribute, then the relation is
1042 		 * already locked.  Otherwise, we lock it now.
1043 		 */
1044 		if (address.classId != RelationRelationId)
1045 		{
1046 			if (IsSharedRelation(address.classId))
1047 				LockSharedObject(address.classId, address.objectId, 0,
1048 								 lockmode);
1049 			else
1050 				LockDatabaseObject(address.classId, address.objectId, 0,
1051 								   lockmode);
1052 		}
1053 
1054 		/*
1055 		 * At this point, we've resolved the name to an OID and locked the
1056 		 * corresponding database object.  However, it's possible that by the
1057 		 * time we acquire the lock on the object, concurrent DDL has modified
1058 		 * the database in such a way that the name we originally looked up no
1059 		 * longer resolves to that OID.
1060 		 *
1061 		 * We can be certain that this isn't an issue if (a) no shared
1062 		 * invalidation messages have been processed or (b) we've locked a
1063 		 * relation somewhere along the line.  All the relation name lookups
1064 		 * in this module ultimately use RangeVarGetRelid() to acquire a
1065 		 * relation lock, and that function protects against the same kinds of
1066 		 * races we're worried about here.  Even when operating on a
1067 		 * constraint, rule, or trigger, we still acquire AccessShareLock on
1068 		 * the relation, which is enough to freeze out any concurrent DDL.
1069 		 *
1070 		 * In all other cases, however, it's possible that the name we looked
1071 		 * up no longer refers to the object we locked, so we retry the lookup
1072 		 * and see whether we get the same answer.
1073 		 */
1074 		if (inval_count == SharedInvalidMessageCounter || relation != NULL)
1075 			break;
1076 		old_address = address;
1077 	}
1078 
1079 	/* Return the object address and the relation. */
1080 	*relp = relation;
1081 	return address;
1082 }
1083 
1084 /*
1085  * Return an ObjectAddress based on a RangeVar and an object name. The
1086  * name of the relation identified by the RangeVar is prepended to the
1087  * (possibly empty) list passed in as object. This is useful to find
1088  * the ObjectAddress of objects that depend on a relation. All other
1089  * considerations are exactly as for get_object_address above.
1090  */
1091 ObjectAddress
1092 get_object_address_rv(ObjectType objtype, RangeVar *rel, List *object,
1093 					  Relation *relp, LOCKMODE lockmode,
1094 					  bool missing_ok)
1095 {
1096 	if (rel)
1097 	{
1098 		object = lcons(makeString(rel->relname), object);
1099 		if (rel->schemaname)
1100 			object = lcons(makeString(rel->schemaname), object);
1101 		if (rel->catalogname)
1102 			object = lcons(makeString(rel->catalogname), object);
1103 	}
1104 
1105 	return get_object_address(objtype, (Node *) object,
1106 							  relp, lockmode, missing_ok);
1107 }
1108 
1109 /*
1110  * Find an ObjectAddress for a type of object that is identified by an
1111  * unqualified name.
1112  */
1113 static ObjectAddress
1114 get_object_address_unqualified(ObjectType objtype,
1115 							   Value *strval, bool missing_ok)
1116 {
1117 	const char *name;
1118 	ObjectAddress address;
1119 
1120 	name = strVal(strval);
1121 
1122 	/* Translate name to OID. */
1123 	switch (objtype)
1124 	{
1125 		case OBJECT_ACCESS_METHOD:
1126 			address.classId = AccessMethodRelationId;
1127 			address.objectId = get_am_oid(name, missing_ok);
1128 			address.objectSubId = 0;
1129 			break;
1130 		case OBJECT_DATABASE:
1131 			address.classId = DatabaseRelationId;
1132 			address.objectId = get_database_oid(name, missing_ok);
1133 			address.objectSubId = 0;
1134 			break;
1135 		case OBJECT_EXTENSION:
1136 			address.classId = ExtensionRelationId;
1137 			address.objectId = get_extension_oid(name, missing_ok);
1138 			address.objectSubId = 0;
1139 			break;
1140 		case OBJECT_TABLESPACE:
1141 			address.classId = TableSpaceRelationId;
1142 			address.objectId = get_tablespace_oid(name, missing_ok);
1143 			address.objectSubId = 0;
1144 			break;
1145 		case OBJECT_ROLE:
1146 			address.classId = AuthIdRelationId;
1147 			address.objectId = get_role_oid(name, missing_ok);
1148 			address.objectSubId = 0;
1149 			break;
1150 		case OBJECT_SCHEMA:
1151 			address.classId = NamespaceRelationId;
1152 			address.objectId = get_namespace_oid(name, missing_ok);
1153 			address.objectSubId = 0;
1154 			break;
1155 		case OBJECT_LANGUAGE:
1156 			address.classId = LanguageRelationId;
1157 			address.objectId = get_language_oid(name, missing_ok);
1158 			address.objectSubId = 0;
1159 			break;
1160 		case OBJECT_FDW:
1161 			address.classId = ForeignDataWrapperRelationId;
1162 			address.objectId = get_foreign_data_wrapper_oid(name, missing_ok);
1163 			address.objectSubId = 0;
1164 			break;
1165 		case OBJECT_FOREIGN_SERVER:
1166 			address.classId = ForeignServerRelationId;
1167 			address.objectId = get_foreign_server_oid(name, missing_ok);
1168 			address.objectSubId = 0;
1169 			break;
1170 		case OBJECT_EVENT_TRIGGER:
1171 			address.classId = EventTriggerRelationId;
1172 			address.objectId = get_event_trigger_oid(name, missing_ok);
1173 			address.objectSubId = 0;
1174 			break;
1175 		case OBJECT_PUBLICATION:
1176 			address.classId = PublicationRelationId;
1177 			address.objectId = get_publication_oid(name, missing_ok);
1178 			address.objectSubId = 0;
1179 			break;
1180 		case OBJECT_SUBSCRIPTION:
1181 			address.classId = SubscriptionRelationId;
1182 			address.objectId = get_subscription_oid(name, missing_ok);
1183 			address.objectSubId = 0;
1184 			break;
1185 		default:
1186 			elog(ERROR, "unrecognized objtype: %d", (int) objtype);
1187 			/* placate compiler, which doesn't know elog won't return */
1188 			address.classId = InvalidOid;
1189 			address.objectId = InvalidOid;
1190 			address.objectSubId = 0;
1191 	}
1192 
1193 	return address;
1194 }
1195 
1196 /*
1197  * Locate a relation by qualified name.
1198  */
1199 static ObjectAddress
1200 get_relation_by_qualified_name(ObjectType objtype, List *object,
1201 							   Relation *relp, LOCKMODE lockmode,
1202 							   bool missing_ok)
1203 {
1204 	Relation	relation;
1205 	ObjectAddress address;
1206 
1207 	address.classId = RelationRelationId;
1208 	address.objectId = InvalidOid;
1209 	address.objectSubId = 0;
1210 
1211 	relation = relation_openrv_extended(makeRangeVarFromNameList(object),
1212 										lockmode, missing_ok);
1213 	if (!relation)
1214 		return address;
1215 
1216 	switch (objtype)
1217 	{
1218 		case OBJECT_INDEX:
1219 			if (relation->rd_rel->relkind != RELKIND_INDEX &&
1220 				relation->rd_rel->relkind != RELKIND_PARTITIONED_INDEX)
1221 				ereport(ERROR,
1222 						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
1223 						 errmsg("\"%s\" is not an index",
1224 								RelationGetRelationName(relation))));
1225 			break;
1226 		case OBJECT_SEQUENCE:
1227 			if (relation->rd_rel->relkind != RELKIND_SEQUENCE)
1228 				ereport(ERROR,
1229 						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
1230 						 errmsg("\"%s\" is not a sequence",
1231 								RelationGetRelationName(relation))));
1232 			break;
1233 		case OBJECT_TABLE:
1234 			if (relation->rd_rel->relkind != RELKIND_RELATION &&
1235 				relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
1236 				ereport(ERROR,
1237 						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
1238 						 errmsg("\"%s\" is not a table",
1239 								RelationGetRelationName(relation))));
1240 			break;
1241 		case OBJECT_VIEW:
1242 			if (relation->rd_rel->relkind != RELKIND_VIEW)
1243 				ereport(ERROR,
1244 						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
1245 						 errmsg("\"%s\" is not a view",
1246 								RelationGetRelationName(relation))));
1247 			break;
1248 		case OBJECT_MATVIEW:
1249 			if (relation->rd_rel->relkind != RELKIND_MATVIEW)
1250 				ereport(ERROR,
1251 						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
1252 						 errmsg("\"%s\" is not a materialized view",
1253 								RelationGetRelationName(relation))));
1254 			break;
1255 		case OBJECT_FOREIGN_TABLE:
1256 			if (relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE)
1257 				ereport(ERROR,
1258 						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
1259 						 errmsg("\"%s\" is not a foreign table",
1260 								RelationGetRelationName(relation))));
1261 			break;
1262 		default:
1263 			elog(ERROR, "unrecognized objtype: %d", (int) objtype);
1264 			break;
1265 	}
1266 
1267 	/* Done. */
1268 	address.objectId = RelationGetRelid(relation);
1269 	*relp = relation;
1270 
1271 	return address;
1272 }
1273 
1274 /*
1275  * Find object address for an object that is attached to a relation.
1276  *
1277  * Note that we take only an AccessShareLock on the relation.  We need not
1278  * pass down the LOCKMODE from get_object_address(), because that is the lock
1279  * mode for the object itself, not the relation to which it is attached.
1280  */
1281 static ObjectAddress
1282 get_object_address_relobject(ObjectType objtype, List *object,
1283 							 Relation *relp, bool missing_ok)
1284 {
1285 	ObjectAddress address;
1286 	Relation	relation = NULL;
1287 	int			nnames;
1288 	const char *depname;
1289 	List	   *relname;
1290 	Oid			reloid;
1291 
1292 	/* Extract name of dependent object. */
1293 	depname = strVal(llast(object));
1294 
1295 	/* Separate relation name from dependent object name. */
1296 	nnames = list_length(object);
1297 	if (nnames < 2)
1298 		ereport(ERROR,
1299 				(errcode(ERRCODE_SYNTAX_ERROR),
1300 				 errmsg("must specify relation and object name")));
1301 
1302 	/* Extract relation name and open relation. */
1303 	relname = list_truncate(list_copy(object), nnames - 1);
1304 	relation = heap_openrv_extended(makeRangeVarFromNameList(relname),
1305 									AccessShareLock,
1306 									missing_ok);
1307 
1308 	reloid = relation ? RelationGetRelid(relation) : InvalidOid;
1309 
1310 	switch (objtype)
1311 	{
1312 		case OBJECT_RULE:
1313 			address.classId = RewriteRelationId;
1314 			address.objectId = relation ?
1315 				get_rewrite_oid(reloid, depname, missing_ok) : InvalidOid;
1316 			address.objectSubId = 0;
1317 			break;
1318 		case OBJECT_TRIGGER:
1319 			address.classId = TriggerRelationId;
1320 			address.objectId = relation ?
1321 				get_trigger_oid(reloid, depname, missing_ok) : InvalidOid;
1322 			address.objectSubId = 0;
1323 			break;
1324 		case OBJECT_TABCONSTRAINT:
1325 			address.classId = ConstraintRelationId;
1326 			address.objectId = relation ?
1327 				get_relation_constraint_oid(reloid, depname, missing_ok) :
1328 				InvalidOid;
1329 			address.objectSubId = 0;
1330 			break;
1331 		case OBJECT_POLICY:
1332 			address.classId = PolicyRelationId;
1333 			address.objectId = relation ?
1334 				get_relation_policy_oid(reloid, depname, missing_ok) :
1335 				InvalidOid;
1336 			address.objectSubId = 0;
1337 			break;
1338 		default:
1339 			elog(ERROR, "unrecognized objtype: %d", (int) objtype);
1340 	}
1341 
1342 	/* Avoid relcache leak when object not found. */
1343 	if (!OidIsValid(address.objectId))
1344 	{
1345 		if (relation != NULL)
1346 			heap_close(relation, AccessShareLock);
1347 
1348 		relation = NULL;		/* department of accident prevention */
1349 		return address;
1350 	}
1351 
1352 	/* Done. */
1353 	*relp = relation;
1354 	return address;
1355 }
1356 
1357 /*
1358  * Find the ObjectAddress for an attribute.
1359  */
1360 static ObjectAddress
1361 get_object_address_attribute(ObjectType objtype, List *object,
1362 							 Relation *relp, LOCKMODE lockmode,
1363 							 bool missing_ok)
1364 {
1365 	ObjectAddress address;
1366 	List	   *relname;
1367 	Oid			reloid;
1368 	Relation	relation;
1369 	const char *attname;
1370 	AttrNumber	attnum;
1371 
1372 	/* Extract relation name and open relation. */
1373 	if (list_length(object) < 2)
1374 		ereport(ERROR,
1375 				(errcode(ERRCODE_SYNTAX_ERROR),
1376 				 errmsg("column name must be qualified")));
1377 	attname = strVal(lfirst(list_tail(object)));
1378 	relname = list_truncate(list_copy(object), list_length(object) - 1);
1379 	/* XXX no missing_ok support here */
1380 	relation = relation_openrv(makeRangeVarFromNameList(relname), lockmode);
1381 	reloid = RelationGetRelid(relation);
1382 
1383 	/* Look up attribute and construct return value. */
1384 	attnum = get_attnum(reloid, attname);
1385 	if (attnum == InvalidAttrNumber)
1386 	{
1387 		if (!missing_ok)
1388 			ereport(ERROR,
1389 					(errcode(ERRCODE_UNDEFINED_COLUMN),
1390 					 errmsg("column \"%s\" of relation \"%s\" does not exist",
1391 							attname, NameListToString(relname))));
1392 
1393 		address.classId = RelationRelationId;
1394 		address.objectId = InvalidOid;
1395 		address.objectSubId = InvalidAttrNumber;
1396 		relation_close(relation, lockmode);
1397 		return address;
1398 	}
1399 
1400 	address.classId = RelationRelationId;
1401 	address.objectId = reloid;
1402 	address.objectSubId = attnum;
1403 
1404 	*relp = relation;
1405 	return address;
1406 }
1407 
1408 /*
1409  * Find the ObjectAddress for an attribute's default value.
1410  */
1411 static ObjectAddress
1412 get_object_address_attrdef(ObjectType objtype, List *object,
1413 						   Relation *relp, LOCKMODE lockmode,
1414 						   bool missing_ok)
1415 {
1416 	ObjectAddress address;
1417 	List	   *relname;
1418 	Oid			reloid;
1419 	Relation	relation;
1420 	const char *attname;
1421 	AttrNumber	attnum;
1422 	TupleDesc	tupdesc;
1423 	Oid			defoid;
1424 
1425 	/* Extract relation name and open relation. */
1426 	if (list_length(object) < 2)
1427 		ereport(ERROR,
1428 				(errcode(ERRCODE_SYNTAX_ERROR),
1429 				 errmsg("column name must be qualified")));
1430 	attname = strVal(llast(object));
1431 	relname = list_truncate(list_copy(object), list_length(object) - 1);
1432 	/* XXX no missing_ok support here */
1433 	relation = relation_openrv(makeRangeVarFromNameList(relname), lockmode);
1434 	reloid = RelationGetRelid(relation);
1435 
1436 	tupdesc = RelationGetDescr(relation);
1437 
1438 	/* Look up attribute number and scan pg_attrdef to find its tuple */
1439 	attnum = get_attnum(reloid, attname);
1440 	defoid = InvalidOid;
1441 	if (attnum != InvalidAttrNumber && tupdesc->constr != NULL)
1442 	{
1443 		Relation	attrdef;
1444 		ScanKeyData keys[2];
1445 		SysScanDesc scan;
1446 		HeapTuple	tup;
1447 
1448 		attrdef = relation_open(AttrDefaultRelationId, AccessShareLock);
1449 		ScanKeyInit(&keys[0],
1450 					Anum_pg_attrdef_adrelid,
1451 					BTEqualStrategyNumber,
1452 					F_OIDEQ,
1453 					ObjectIdGetDatum(reloid));
1454 		ScanKeyInit(&keys[1],
1455 					Anum_pg_attrdef_adnum,
1456 					BTEqualStrategyNumber,
1457 					F_INT2EQ,
1458 					Int16GetDatum(attnum));
1459 		scan = systable_beginscan(attrdef, AttrDefaultIndexId, true,
1460 								  NULL, 2, keys);
1461 		if (HeapTupleIsValid(tup = systable_getnext(scan)))
1462 			defoid = HeapTupleGetOid(tup);
1463 
1464 		systable_endscan(scan);
1465 		relation_close(attrdef, AccessShareLock);
1466 	}
1467 	if (!OidIsValid(defoid))
1468 	{
1469 		if (!missing_ok)
1470 			ereport(ERROR,
1471 					(errcode(ERRCODE_UNDEFINED_COLUMN),
1472 					 errmsg("default value for column \"%s\" of relation \"%s\" does not exist",
1473 							attname, NameListToString(relname))));
1474 
1475 		address.classId = AttrDefaultRelationId;
1476 		address.objectId = InvalidOid;
1477 		address.objectSubId = InvalidAttrNumber;
1478 		relation_close(relation, lockmode);
1479 		return address;
1480 	}
1481 
1482 	address.classId = AttrDefaultRelationId;
1483 	address.objectId = defoid;
1484 	address.objectSubId = 0;
1485 
1486 	*relp = relation;
1487 	return address;
1488 }
1489 
1490 /*
1491  * Find the ObjectAddress for a type or domain
1492  */
1493 static ObjectAddress
1494 get_object_address_type(ObjectType objtype, TypeName *typename, bool missing_ok)
1495 {
1496 	ObjectAddress address;
1497 	Type		tup;
1498 
1499 	address.classId = TypeRelationId;
1500 	address.objectId = InvalidOid;
1501 	address.objectSubId = 0;
1502 
1503 	tup = LookupTypeName(NULL, typename, NULL, missing_ok);
1504 	if (!HeapTupleIsValid(tup))
1505 	{
1506 		if (!missing_ok)
1507 			ereport(ERROR,
1508 					(errcode(ERRCODE_UNDEFINED_OBJECT),
1509 					 errmsg("type \"%s\" does not exist",
1510 							TypeNameToString(typename))));
1511 		return address;
1512 	}
1513 	address.objectId = typeTypeId(tup);
1514 
1515 	if (objtype == OBJECT_DOMAIN)
1516 	{
1517 		if (((Form_pg_type) GETSTRUCT(tup))->typtype != TYPTYPE_DOMAIN)
1518 			ereport(ERROR,
1519 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
1520 					 errmsg("\"%s\" is not a domain",
1521 							TypeNameToString(typename))));
1522 	}
1523 
1524 	ReleaseSysCache(tup);
1525 
1526 	return address;
1527 }
1528 
1529 /*
1530  * Find the ObjectAddress for an opclass or opfamily.
1531  */
1532 static ObjectAddress
1533 get_object_address_opcf(ObjectType objtype, List *object, bool missing_ok)
1534 {
1535 	Oid			amoid;
1536 	ObjectAddress address;
1537 
1538 	/* XXX no missing_ok support here */
1539 	amoid = get_index_am_oid(strVal(linitial(object)), false);
1540 	object = list_copy_tail(object, 1);
1541 
1542 	switch (objtype)
1543 	{
1544 		case OBJECT_OPCLASS:
1545 			address.classId = OperatorClassRelationId;
1546 			address.objectId = get_opclass_oid(amoid, object, missing_ok);
1547 			address.objectSubId = 0;
1548 			break;
1549 		case OBJECT_OPFAMILY:
1550 			address.classId = OperatorFamilyRelationId;
1551 			address.objectId = get_opfamily_oid(amoid, object, missing_ok);
1552 			address.objectSubId = 0;
1553 			break;
1554 		default:
1555 			elog(ERROR, "unrecognized objtype: %d", (int) objtype);
1556 			/* placate compiler, which doesn't know elog won't return */
1557 			address.classId = InvalidOid;
1558 			address.objectId = InvalidOid;
1559 			address.objectSubId = 0;
1560 	}
1561 
1562 	return address;
1563 }
1564 
1565 /*
1566  * Find the ObjectAddress for an opclass/opfamily member.
1567  *
1568  * (The returned address corresponds to a pg_amop/pg_amproc object).
1569  */
1570 static ObjectAddress
1571 get_object_address_opf_member(ObjectType objtype,
1572 							  List *object, bool missing_ok)
1573 {
1574 	ObjectAddress famaddr;
1575 	ObjectAddress address;
1576 	ListCell   *cell;
1577 	List	   *copy;
1578 	TypeName   *typenames[2];
1579 	Oid			typeoids[2];
1580 	int			membernum;
1581 	int			i;
1582 
1583 	/*
1584 	 * The last element of the object list contains the strategy or procedure
1585 	 * number.  We need to strip that out before getting the opclass/family
1586 	 * address.  The rest can be used directly by get_object_address_opcf().
1587 	 */
1588 	membernum = atoi(strVal(llast(linitial(object))));
1589 	copy = list_truncate(list_copy(linitial(object)), list_length(linitial(object)) - 1);
1590 
1591 	/* no missing_ok support here */
1592 	famaddr = get_object_address_opcf(OBJECT_OPFAMILY, copy, false);
1593 
1594 	/* find out left/right type names and OIDs */
1595 	typenames[0] = typenames[1] = NULL;
1596 	typeoids[0] = typeoids[1] = InvalidOid;
1597 	i = 0;
1598 	foreach(cell, lsecond(object))
1599 	{
1600 		ObjectAddress typaddr;
1601 
1602 		typenames[i] = lfirst_node(TypeName, cell);
1603 		typaddr = get_object_address_type(OBJECT_TYPE, typenames[i], missing_ok);
1604 		typeoids[i] = typaddr.objectId;
1605 		if (++i >= 2)
1606 			break;
1607 	}
1608 
1609 	switch (objtype)
1610 	{
1611 		case OBJECT_AMOP:
1612 			{
1613 				HeapTuple	tp;
1614 
1615 				ObjectAddressSet(address, AccessMethodOperatorRelationId,
1616 								 InvalidOid);
1617 
1618 				tp = SearchSysCache4(AMOPSTRATEGY,
1619 									 ObjectIdGetDatum(famaddr.objectId),
1620 									 ObjectIdGetDatum(typeoids[0]),
1621 									 ObjectIdGetDatum(typeoids[1]),
1622 									 Int16GetDatum(membernum));
1623 				if (!HeapTupleIsValid(tp))
1624 				{
1625 					if (!missing_ok)
1626 						ereport(ERROR,
1627 								(errcode(ERRCODE_UNDEFINED_OBJECT),
1628 								 errmsg("operator %d (%s, %s) of %s does not exist",
1629 										membernum,
1630 										TypeNameToString(typenames[0]),
1631 										TypeNameToString(typenames[1]),
1632 										getObjectDescription(&famaddr))));
1633 				}
1634 				else
1635 				{
1636 					address.objectId = HeapTupleGetOid(tp);
1637 					ReleaseSysCache(tp);
1638 				}
1639 			}
1640 			break;
1641 
1642 		case OBJECT_AMPROC:
1643 			{
1644 				HeapTuple	tp;
1645 
1646 				ObjectAddressSet(address, AccessMethodProcedureRelationId,
1647 								 InvalidOid);
1648 
1649 				tp = SearchSysCache4(AMPROCNUM,
1650 									 ObjectIdGetDatum(famaddr.objectId),
1651 									 ObjectIdGetDatum(typeoids[0]),
1652 									 ObjectIdGetDatum(typeoids[1]),
1653 									 Int16GetDatum(membernum));
1654 				if (!HeapTupleIsValid(tp))
1655 				{
1656 					if (!missing_ok)
1657 						ereport(ERROR,
1658 								(errcode(ERRCODE_UNDEFINED_OBJECT),
1659 								 errmsg("function %d (%s, %s) of %s does not exist",
1660 										membernum,
1661 										TypeNameToString(typenames[0]),
1662 										TypeNameToString(typenames[1]),
1663 										getObjectDescription(&famaddr))));
1664 				}
1665 				else
1666 				{
1667 					address.objectId = HeapTupleGetOid(tp);
1668 					ReleaseSysCache(tp);
1669 				}
1670 			}
1671 			break;
1672 		default:
1673 			elog(ERROR, "unrecognized objtype: %d", (int) objtype);
1674 	}
1675 
1676 	return address;
1677 }
1678 
1679 /*
1680  * Find the ObjectAddress for a user mapping.
1681  */
1682 static ObjectAddress
1683 get_object_address_usermapping(List *object, bool missing_ok)
1684 {
1685 	ObjectAddress address;
1686 	Oid			userid;
1687 	char	   *username;
1688 	char	   *servername;
1689 	ForeignServer *server;
1690 	HeapTuple	tp;
1691 
1692 	ObjectAddressSet(address, UserMappingRelationId, InvalidOid);
1693 
1694 	/* fetch string names from input lists, for error messages */
1695 	username = strVal(linitial(object));
1696 	servername = strVal(lsecond(object));
1697 
1698 	/* look up pg_authid OID of mapped user; InvalidOid if PUBLIC */
1699 	if (strcmp(username, "public") == 0)
1700 		userid = InvalidOid;
1701 	else
1702 	{
1703 		tp = SearchSysCache1(AUTHNAME,
1704 							 CStringGetDatum(username));
1705 		if (!HeapTupleIsValid(tp))
1706 		{
1707 			if (!missing_ok)
1708 				ereport(ERROR,
1709 						(errcode(ERRCODE_UNDEFINED_OBJECT),
1710 						 errmsg("user mapping for user \"%s\" on server \"%s\" does not exist",
1711 								username, servername)));
1712 			return address;
1713 		}
1714 		userid = HeapTupleGetOid(tp);
1715 		ReleaseSysCache(tp);
1716 	}
1717 
1718 	/* Now look up the pg_user_mapping tuple */
1719 	server = GetForeignServerByName(servername, true);
1720 	if (!server)
1721 	{
1722 		if (!missing_ok)
1723 			ereport(ERROR,
1724 					(errcode(ERRCODE_UNDEFINED_OBJECT),
1725 					 errmsg("server \"%s\" does not exist", servername)));
1726 		return address;
1727 	}
1728 	tp = SearchSysCache2(USERMAPPINGUSERSERVER,
1729 						 ObjectIdGetDatum(userid),
1730 						 ObjectIdGetDatum(server->serverid));
1731 	if (!HeapTupleIsValid(tp))
1732 	{
1733 		if (!missing_ok)
1734 			ereport(ERROR,
1735 					(errcode(ERRCODE_UNDEFINED_OBJECT),
1736 					 errmsg("user mapping for user \"%s\" on server \"%s\" does not exist",
1737 							username, servername)));
1738 		return address;
1739 	}
1740 
1741 	address.objectId = HeapTupleGetOid(tp);
1742 
1743 	ReleaseSysCache(tp);
1744 
1745 	return address;
1746 }
1747 
1748 /*
1749  * Find the ObjectAddress for a publication relation.  The first element of
1750  * the object parameter is the relation name, the second is the
1751  * publication name.
1752  */
1753 static ObjectAddress
1754 get_object_address_publication_rel(List *object,
1755 								   Relation *relp, bool missing_ok)
1756 {
1757 	ObjectAddress address;
1758 	Relation	relation;
1759 	List	   *relname;
1760 	char	   *pubname;
1761 	Publication *pub;
1762 
1763 	ObjectAddressSet(address, PublicationRelRelationId, InvalidOid);
1764 
1765 	relname = linitial(object);
1766 	relation = relation_openrv_extended(makeRangeVarFromNameList(relname),
1767 										AccessShareLock, missing_ok);
1768 	if (!relation)
1769 		return address;
1770 
1771 	/* fetch publication name from input list */
1772 	pubname = strVal(lsecond(object));
1773 
1774 	/* Now look up the pg_publication tuple */
1775 	pub = GetPublicationByName(pubname, missing_ok);
1776 	if (!pub)
1777 	{
1778 		relation_close(relation, AccessShareLock);
1779 		return address;
1780 	}
1781 
1782 	/* Find the publication relation mapping in syscache. */
1783 	address.objectId =
1784 		GetSysCacheOid2(PUBLICATIONRELMAP,
1785 						ObjectIdGetDatum(RelationGetRelid(relation)),
1786 						ObjectIdGetDatum(pub->oid));
1787 	if (!OidIsValid(address.objectId))
1788 	{
1789 		if (!missing_ok)
1790 			ereport(ERROR,
1791 					(errcode(ERRCODE_UNDEFINED_OBJECT),
1792 					 errmsg("publication relation \"%s\" in publication \"%s\" does not exist",
1793 							RelationGetRelationName(relation), pubname)));
1794 		relation_close(relation, AccessShareLock);
1795 		return address;
1796 	}
1797 
1798 	*relp = relation;
1799 	return address;
1800 }
1801 
1802 /*
1803  * Find the ObjectAddress for a default ACL.
1804  */
1805 static ObjectAddress
1806 get_object_address_defacl(List *object, bool missing_ok)
1807 {
1808 	HeapTuple	tp;
1809 	Oid			userid;
1810 	Oid			schemaid;
1811 	char	   *username;
1812 	char	   *schema;
1813 	char		objtype;
1814 	char	   *objtype_str;
1815 	ObjectAddress address;
1816 
1817 	ObjectAddressSet(address, DefaultAclRelationId, InvalidOid);
1818 
1819 	/*
1820 	 * First figure out the textual attributes so that they can be used for
1821 	 * error reporting.
1822 	 */
1823 	username = strVal(lsecond(object));
1824 	if (list_length(object) >= 3)
1825 		schema = (char *) strVal(lthird(object));
1826 	else
1827 		schema = NULL;
1828 
1829 	/*
1830 	 * Decode defaclobjtype.  Only first char is considered; the rest of the
1831 	 * string, if any, is blissfully ignored.
1832 	 */
1833 	objtype = ((char *) strVal(linitial(object)))[0];
1834 	switch (objtype)
1835 	{
1836 		case DEFACLOBJ_RELATION:
1837 			objtype_str = "tables";
1838 			break;
1839 		case DEFACLOBJ_SEQUENCE:
1840 			objtype_str = "sequences";
1841 			break;
1842 		case DEFACLOBJ_FUNCTION:
1843 			objtype_str = "functions";
1844 			break;
1845 		case DEFACLOBJ_TYPE:
1846 			objtype_str = "types";
1847 			break;
1848 		case DEFACLOBJ_NAMESPACE:
1849 			objtype_str = "schemas";
1850 			break;
1851 		default:
1852 			ereport(ERROR,
1853 					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1854 					 errmsg("unrecognized default ACL object type \"%c\"", objtype),
1855 					 errhint("Valid object types are \"%c\", \"%c\", \"%c\", \"%c\", \"%c\".",
1856 							 DEFACLOBJ_RELATION,
1857 							 DEFACLOBJ_SEQUENCE,
1858 							 DEFACLOBJ_FUNCTION,
1859 							 DEFACLOBJ_TYPE,
1860 							 DEFACLOBJ_NAMESPACE)));
1861 	}
1862 
1863 	/*
1864 	 * Look up user ID.  Behave as "default ACL not found" if the user doesn't
1865 	 * exist.
1866 	 */
1867 	tp = SearchSysCache1(AUTHNAME,
1868 						 CStringGetDatum(username));
1869 	if (!HeapTupleIsValid(tp))
1870 		goto not_found;
1871 	userid = HeapTupleGetOid(tp);
1872 	ReleaseSysCache(tp);
1873 
1874 	/*
1875 	 * If a schema name was given, look up its OID.  If it doesn't exist,
1876 	 * behave as "default ACL not found".
1877 	 */
1878 	if (schema)
1879 	{
1880 		schemaid = get_namespace_oid(schema, true);
1881 		if (schemaid == InvalidOid)
1882 			goto not_found;
1883 	}
1884 	else
1885 		schemaid = InvalidOid;
1886 
1887 	/* Finally, look up the pg_default_acl object */
1888 	tp = SearchSysCache3(DEFACLROLENSPOBJ,
1889 						 ObjectIdGetDatum(userid),
1890 						 ObjectIdGetDatum(schemaid),
1891 						 CharGetDatum(objtype));
1892 	if (!HeapTupleIsValid(tp))
1893 		goto not_found;
1894 
1895 	address.objectId = HeapTupleGetOid(tp);
1896 	ReleaseSysCache(tp);
1897 
1898 	return address;
1899 
1900 not_found:
1901 	if (!missing_ok)
1902 	{
1903 		if (schema)
1904 			ereport(ERROR,
1905 					(errcode(ERRCODE_UNDEFINED_OBJECT),
1906 					 errmsg("default ACL for user \"%s\" in schema \"%s\" on %s does not exist",
1907 							username, schema, objtype_str)));
1908 		else
1909 			ereport(ERROR,
1910 					(errcode(ERRCODE_UNDEFINED_OBJECT),
1911 					 errmsg("default ACL for user \"%s\" on %s does not exist",
1912 							username, objtype_str)));
1913 	}
1914 	return address;
1915 }
1916 
1917 /*
1918  * Convert an array of TEXT into a List of string Values, as emitted by the
1919  * parser, which is what get_object_address uses as input.
1920  */
1921 static List *
1922 textarray_to_strvaluelist(ArrayType *arr)
1923 {
1924 	Datum	   *elems;
1925 	bool	   *nulls;
1926 	int			nelems;
1927 	List	   *list = NIL;
1928 	int			i;
1929 
1930 	deconstruct_array(arr, TEXTOID, -1, false, 'i',
1931 					  &elems, &nulls, &nelems);
1932 
1933 	for (i = 0; i < nelems; i++)
1934 	{
1935 		if (nulls[i])
1936 			ereport(ERROR,
1937 					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1938 					 errmsg("name or argument lists may not contain nulls")));
1939 		list = lappend(list, makeString(TextDatumGetCString(elems[i])));
1940 	}
1941 
1942 	return list;
1943 }
1944 
1945 /*
1946  * SQL-callable version of get_object_address
1947  */
1948 Datum
1949 pg_get_object_address(PG_FUNCTION_ARGS)
1950 {
1951 	char	   *ttype = TextDatumGetCString(PG_GETARG_DATUM(0));
1952 	ArrayType  *namearr = PG_GETARG_ARRAYTYPE_P(1);
1953 	ArrayType  *argsarr = PG_GETARG_ARRAYTYPE_P(2);
1954 	int			itype;
1955 	ObjectType	type;
1956 	List	   *name = NIL;
1957 	TypeName   *typename = NULL;
1958 	List	   *args = NIL;
1959 	Node	   *objnode = NULL;
1960 	ObjectAddress addr;
1961 	TupleDesc	tupdesc;
1962 	Datum		values[3];
1963 	bool		nulls[3];
1964 	HeapTuple	htup;
1965 	Relation	relation;
1966 
1967 	/* Decode object type, raise error if unknown */
1968 	itype = read_objtype_from_string(ttype);
1969 	if (itype < 0)
1970 		ereport(ERROR,
1971 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1972 				 errmsg("unsupported object type \"%s\"", ttype)));
1973 	type = (ObjectType) itype;
1974 
1975 	/*
1976 	 * Convert the text array to the representation appropriate for the given
1977 	 * object type.  Most use a simple string Values list, but there are some
1978 	 * exceptions.
1979 	 */
1980 	if (type == OBJECT_TYPE || type == OBJECT_DOMAIN || type == OBJECT_CAST ||
1981 		type == OBJECT_TRANSFORM || type == OBJECT_DOMCONSTRAINT)
1982 	{
1983 		Datum	   *elems;
1984 		bool	   *nulls;
1985 		int			nelems;
1986 
1987 		deconstruct_array(namearr, TEXTOID, -1, false, 'i',
1988 						  &elems, &nulls, &nelems);
1989 		if (nelems != 1)
1990 			ereport(ERROR,
1991 					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1992 					 errmsg("name list length must be exactly %d", 1)));
1993 		if (nulls[0])
1994 			ereport(ERROR,
1995 					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1996 					 errmsg("name or argument lists may not contain nulls")));
1997 		typename = typeStringToTypeName(TextDatumGetCString(elems[0]));
1998 	}
1999 	else if (type == OBJECT_LARGEOBJECT)
2000 	{
2001 		Datum	   *elems;
2002 		bool	   *nulls;
2003 		int			nelems;
2004 
2005 		deconstruct_array(namearr, TEXTOID, -1, false, 'i',
2006 						  &elems, &nulls, &nelems);
2007 		if (nelems != 1)
2008 			ereport(ERROR,
2009 					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2010 					 errmsg("name list length must be exactly %d", 1)));
2011 		if (nulls[0])
2012 			ereport(ERROR,
2013 					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2014 					 errmsg("large object OID may not be null")));
2015 		objnode = (Node *) makeFloat(TextDatumGetCString(elems[0]));
2016 	}
2017 	else
2018 	{
2019 		name = textarray_to_strvaluelist(namearr);
2020 		if (list_length(name) < 1)
2021 			ereport(ERROR,
2022 					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2023 					 errmsg("name list length must be at least %d", 1)));
2024 	}
2025 
2026 	/*
2027 	 * If args are given, decode them according to the object type.
2028 	 */
2029 	if (type == OBJECT_AGGREGATE ||
2030 		type == OBJECT_FUNCTION ||
2031 		type == OBJECT_PROCEDURE ||
2032 		type == OBJECT_ROUTINE ||
2033 		type == OBJECT_OPERATOR ||
2034 		type == OBJECT_CAST ||
2035 		type == OBJECT_AMOP ||
2036 		type == OBJECT_AMPROC)
2037 	{
2038 		/* in these cases, the args list must be of TypeName */
2039 		Datum	   *elems;
2040 		bool	   *nulls;
2041 		int			nelems;
2042 		int			i;
2043 
2044 		deconstruct_array(argsarr, TEXTOID, -1, false, 'i',
2045 						  &elems, &nulls, &nelems);
2046 
2047 		args = NIL;
2048 		for (i = 0; i < nelems; i++)
2049 		{
2050 			if (nulls[i])
2051 				ereport(ERROR,
2052 						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2053 						 errmsg("name or argument lists may not contain nulls")));
2054 			args = lappend(args,
2055 						   typeStringToTypeName(TextDatumGetCString(elems[i])));
2056 		}
2057 	}
2058 	else
2059 	{
2060 		/* For all other object types, use string Values */
2061 		args = textarray_to_strvaluelist(argsarr);
2062 	}
2063 
2064 	/*
2065 	 * get_object_address is pretty sensitive to the length of its input
2066 	 * lists; check that they're what it wants.
2067 	 */
2068 	switch (type)
2069 	{
2070 		case OBJECT_DOMCONSTRAINT:
2071 		case OBJECT_CAST:
2072 		case OBJECT_USER_MAPPING:
2073 		case OBJECT_PUBLICATION_REL:
2074 		case OBJECT_DEFACL:
2075 		case OBJECT_TRANSFORM:
2076 			if (list_length(args) != 1)
2077 				ereport(ERROR,
2078 						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2079 						 errmsg("argument list length must be exactly %d", 1)));
2080 			break;
2081 		case OBJECT_OPFAMILY:
2082 		case OBJECT_OPCLASS:
2083 			if (list_length(name) < 2)
2084 				ereport(ERROR,
2085 						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2086 						 errmsg("name list length must be at least %d", 2)));
2087 			break;
2088 		case OBJECT_AMOP:
2089 		case OBJECT_AMPROC:
2090 			if (list_length(name) < 3)
2091 				ereport(ERROR,
2092 						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2093 						 errmsg("name list length must be at least %d", 3)));
2094 			/* fall through to check args length */
2095 			/* FALLTHROUGH */
2096 		case OBJECT_OPERATOR:
2097 			if (list_length(args) != 2)
2098 				ereport(ERROR,
2099 						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2100 						 errmsg("argument list length must be exactly %d", 2)));
2101 			break;
2102 		default:
2103 			break;
2104 	}
2105 
2106 	/*
2107 	 * Now build the Node type that get_object_address() expects for the given
2108 	 * type.
2109 	 */
2110 	switch (type)
2111 	{
2112 		case OBJECT_TABLE:
2113 		case OBJECT_SEQUENCE:
2114 		case OBJECT_VIEW:
2115 		case OBJECT_MATVIEW:
2116 		case OBJECT_INDEX:
2117 		case OBJECT_FOREIGN_TABLE:
2118 		case OBJECT_COLUMN:
2119 		case OBJECT_ATTRIBUTE:
2120 		case OBJECT_COLLATION:
2121 		case OBJECT_CONVERSION:
2122 		case OBJECT_STATISTIC_EXT:
2123 		case OBJECT_TSPARSER:
2124 		case OBJECT_TSDICTIONARY:
2125 		case OBJECT_TSTEMPLATE:
2126 		case OBJECT_TSCONFIGURATION:
2127 		case OBJECT_DEFAULT:
2128 		case OBJECT_POLICY:
2129 		case OBJECT_RULE:
2130 		case OBJECT_TRIGGER:
2131 		case OBJECT_TABCONSTRAINT:
2132 		case OBJECT_OPCLASS:
2133 		case OBJECT_OPFAMILY:
2134 			objnode = (Node *) name;
2135 			break;
2136 		case OBJECT_ACCESS_METHOD:
2137 		case OBJECT_DATABASE:
2138 		case OBJECT_EVENT_TRIGGER:
2139 		case OBJECT_EXTENSION:
2140 		case OBJECT_FDW:
2141 		case OBJECT_FOREIGN_SERVER:
2142 		case OBJECT_LANGUAGE:
2143 		case OBJECT_PUBLICATION:
2144 		case OBJECT_ROLE:
2145 		case OBJECT_SCHEMA:
2146 		case OBJECT_SUBSCRIPTION:
2147 		case OBJECT_TABLESPACE:
2148 			if (list_length(name) != 1)
2149 				ereport(ERROR,
2150 						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2151 						 errmsg("name list length must be exactly %d", 1)));
2152 			objnode = linitial(name);
2153 			break;
2154 		case OBJECT_TYPE:
2155 		case OBJECT_DOMAIN:
2156 			objnode = (Node *) typename;
2157 			break;
2158 		case OBJECT_CAST:
2159 		case OBJECT_DOMCONSTRAINT:
2160 		case OBJECT_TRANSFORM:
2161 			objnode = (Node *) list_make2(typename, linitial(args));
2162 			break;
2163 		case OBJECT_PUBLICATION_REL:
2164 			objnode = (Node *) list_make2(name, linitial(args));
2165 			break;
2166 		case OBJECT_USER_MAPPING:
2167 			objnode = (Node *) list_make2(linitial(name), linitial(args));
2168 			break;
2169 		case OBJECT_DEFACL:
2170 			objnode = (Node *) lcons(linitial(args), name);
2171 			break;
2172 		case OBJECT_AMOP:
2173 		case OBJECT_AMPROC:
2174 			objnode = (Node *) list_make2(name, args);
2175 			break;
2176 		case OBJECT_FUNCTION:
2177 		case OBJECT_PROCEDURE:
2178 		case OBJECT_ROUTINE:
2179 		case OBJECT_AGGREGATE:
2180 		case OBJECT_OPERATOR:
2181 			{
2182 				ObjectWithArgs *owa = makeNode(ObjectWithArgs);
2183 
2184 				owa->objname = name;
2185 				owa->objargs = args;
2186 				objnode = (Node *) owa;
2187 				break;
2188 			}
2189 		case OBJECT_LARGEOBJECT:
2190 			/* already handled above */
2191 			break;
2192 			/* no default, to let compiler warn about missing case */
2193 	}
2194 
2195 	if (objnode == NULL)
2196 		elog(ERROR, "unrecognized object type: %d", type);
2197 
2198 	addr = get_object_address(type, objnode,
2199 							  &relation, AccessShareLock, false);
2200 
2201 	/* We don't need the relcache entry, thank you very much */
2202 	if (relation)
2203 		relation_close(relation, AccessShareLock);
2204 
2205 	tupdesc = CreateTemplateTupleDesc(3, false);
2206 	TupleDescInitEntry(tupdesc, (AttrNumber) 1, "classid",
2207 					   OIDOID, -1, 0);
2208 	TupleDescInitEntry(tupdesc, (AttrNumber) 2, "objid",
2209 					   OIDOID, -1, 0);
2210 	TupleDescInitEntry(tupdesc, (AttrNumber) 3, "objsubid",
2211 					   INT4OID, -1, 0);
2212 	tupdesc = BlessTupleDesc(tupdesc);
2213 
2214 	values[0] = ObjectIdGetDatum(addr.classId);
2215 	values[1] = ObjectIdGetDatum(addr.objectId);
2216 	values[2] = Int32GetDatum(addr.objectSubId);
2217 	nulls[0] = false;
2218 	nulls[1] = false;
2219 	nulls[2] = false;
2220 
2221 	htup = heap_form_tuple(tupdesc, values, nulls);
2222 
2223 	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
2224 }
2225 
2226 /*
2227  * Check ownership of an object previously identified by get_object_address.
2228  */
2229 void
2230 check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address,
2231 					   Node *object, Relation relation)
2232 {
2233 	switch (objtype)
2234 	{
2235 		case OBJECT_INDEX:
2236 		case OBJECT_SEQUENCE:
2237 		case OBJECT_TABLE:
2238 		case OBJECT_VIEW:
2239 		case OBJECT_MATVIEW:
2240 		case OBJECT_FOREIGN_TABLE:
2241 		case OBJECT_COLUMN:
2242 		case OBJECT_RULE:
2243 		case OBJECT_TRIGGER:
2244 		case OBJECT_POLICY:
2245 		case OBJECT_TABCONSTRAINT:
2246 			if (!pg_class_ownercheck(RelationGetRelid(relation), roleid))
2247 				aclcheck_error(ACLCHECK_NOT_OWNER, objtype,
2248 							   RelationGetRelationName(relation));
2249 			break;
2250 		case OBJECT_DATABASE:
2251 			if (!pg_database_ownercheck(address.objectId, roleid))
2252 				aclcheck_error(ACLCHECK_NOT_OWNER, objtype,
2253 							   strVal((Value *) object));
2254 			break;
2255 		case OBJECT_TYPE:
2256 		case OBJECT_DOMAIN:
2257 		case OBJECT_ATTRIBUTE:
2258 			if (!pg_type_ownercheck(address.objectId, roleid))
2259 				aclcheck_error_type(ACLCHECK_NOT_OWNER, address.objectId);
2260 			break;
2261 		case OBJECT_DOMCONSTRAINT:
2262 			{
2263 				HeapTuple	tuple;
2264 				Oid			contypid;
2265 
2266 				tuple = SearchSysCache1(CONSTROID,
2267 										ObjectIdGetDatum(address.objectId));
2268 				if (!HeapTupleIsValid(tuple))
2269 					elog(ERROR, "constraint with OID %u does not exist",
2270 						 address.objectId);
2271 
2272 				contypid = ((Form_pg_constraint) GETSTRUCT(tuple))->contypid;
2273 
2274 				ReleaseSysCache(tuple);
2275 
2276 				/*
2277 				 * Fallback to type ownership check in this case as this is
2278 				 * what domain constraints rely on.
2279 				 */
2280 				if (!pg_type_ownercheck(contypid, roleid))
2281 					aclcheck_error_type(ACLCHECK_NOT_OWNER, contypid);
2282 			}
2283 			break;
2284 		case OBJECT_AGGREGATE:
2285 		case OBJECT_FUNCTION:
2286 		case OBJECT_PROCEDURE:
2287 		case OBJECT_ROUTINE:
2288 			if (!pg_proc_ownercheck(address.objectId, roleid))
2289 				aclcheck_error(ACLCHECK_NOT_OWNER, objtype,
2290 							   NameListToString((castNode(ObjectWithArgs, object))->objname));
2291 			break;
2292 		case OBJECT_OPERATOR:
2293 			if (!pg_oper_ownercheck(address.objectId, roleid))
2294 				aclcheck_error(ACLCHECK_NOT_OWNER, objtype,
2295 							   NameListToString((castNode(ObjectWithArgs, object))->objname));
2296 			break;
2297 		case OBJECT_SCHEMA:
2298 			if (!pg_namespace_ownercheck(address.objectId, roleid))
2299 				aclcheck_error(ACLCHECK_NOT_OWNER, objtype,
2300 							   strVal((Value *) object));
2301 			break;
2302 		case OBJECT_COLLATION:
2303 			if (!pg_collation_ownercheck(address.objectId, roleid))
2304 				aclcheck_error(ACLCHECK_NOT_OWNER, objtype,
2305 							   NameListToString(castNode(List, object)));
2306 			break;
2307 		case OBJECT_CONVERSION:
2308 			if (!pg_conversion_ownercheck(address.objectId, roleid))
2309 				aclcheck_error(ACLCHECK_NOT_OWNER, objtype,
2310 							   NameListToString(castNode(List, object)));
2311 			break;
2312 		case OBJECT_EXTENSION:
2313 			if (!pg_extension_ownercheck(address.objectId, roleid))
2314 				aclcheck_error(ACLCHECK_NOT_OWNER, objtype,
2315 							   strVal((Value *) object));
2316 			break;
2317 		case OBJECT_FDW:
2318 			if (!pg_foreign_data_wrapper_ownercheck(address.objectId, roleid))
2319 				aclcheck_error(ACLCHECK_NOT_OWNER, objtype,
2320 							   strVal((Value *) object));
2321 			break;
2322 		case OBJECT_FOREIGN_SERVER:
2323 			if (!pg_foreign_server_ownercheck(address.objectId, roleid))
2324 				aclcheck_error(ACLCHECK_NOT_OWNER, objtype,
2325 							   strVal((Value *) object));
2326 			break;
2327 		case OBJECT_EVENT_TRIGGER:
2328 			if (!pg_event_trigger_ownercheck(address.objectId, roleid))
2329 				aclcheck_error(ACLCHECK_NOT_OWNER, objtype,
2330 							   strVal((Value *) object));
2331 			break;
2332 		case OBJECT_LANGUAGE:
2333 			if (!pg_language_ownercheck(address.objectId, roleid))
2334 				aclcheck_error(ACLCHECK_NOT_OWNER, objtype,
2335 							   strVal((Value *) object));
2336 			break;
2337 		case OBJECT_OPCLASS:
2338 			if (!pg_opclass_ownercheck(address.objectId, roleid))
2339 				aclcheck_error(ACLCHECK_NOT_OWNER, objtype,
2340 							   NameListToString(castNode(List, object)));
2341 			break;
2342 		case OBJECT_OPFAMILY:
2343 			if (!pg_opfamily_ownercheck(address.objectId, roleid))
2344 				aclcheck_error(ACLCHECK_NOT_OWNER, objtype,
2345 							   NameListToString(castNode(List, object)));
2346 			break;
2347 		case OBJECT_LARGEOBJECT:
2348 			if (!lo_compat_privileges &&
2349 				!pg_largeobject_ownercheck(address.objectId, roleid))
2350 				ereport(ERROR,
2351 						(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2352 						 errmsg("must be owner of large object %u",
2353 								address.objectId)));
2354 			break;
2355 		case OBJECT_CAST:
2356 			{
2357 				/* We can only check permissions on the source/target types */
2358 				TypeName   *sourcetype = linitial_node(TypeName, castNode(List, object));
2359 				TypeName   *targettype = lsecond_node(TypeName, castNode(List, object));
2360 				Oid			sourcetypeid = typenameTypeId(NULL, sourcetype);
2361 				Oid			targettypeid = typenameTypeId(NULL, targettype);
2362 
2363 				if (!pg_type_ownercheck(sourcetypeid, roleid)
2364 					&& !pg_type_ownercheck(targettypeid, roleid))
2365 					ereport(ERROR,
2366 							(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2367 							 errmsg("must be owner of type %s or type %s",
2368 									format_type_be(sourcetypeid),
2369 									format_type_be(targettypeid))));
2370 			}
2371 			break;
2372 		case OBJECT_PUBLICATION:
2373 			if (!pg_publication_ownercheck(address.objectId, roleid))
2374 				aclcheck_error(ACLCHECK_NOT_OWNER, objtype,
2375 							   strVal((Value *) object));
2376 			break;
2377 		case OBJECT_SUBSCRIPTION:
2378 			if (!pg_subscription_ownercheck(address.objectId, roleid))
2379 				aclcheck_error(ACLCHECK_NOT_OWNER, objtype,
2380 							   strVal((Value *) object));
2381 			break;
2382 		case OBJECT_TRANSFORM:
2383 			{
2384 				TypeName   *typename = linitial_node(TypeName, castNode(List, object));
2385 				Oid			typeid = typenameTypeId(NULL, typename);
2386 
2387 				if (!pg_type_ownercheck(typeid, roleid))
2388 					aclcheck_error_type(ACLCHECK_NOT_OWNER, typeid);
2389 			}
2390 			break;
2391 		case OBJECT_TABLESPACE:
2392 			if (!pg_tablespace_ownercheck(address.objectId, roleid))
2393 				aclcheck_error(ACLCHECK_NOT_OWNER, objtype,
2394 							   strVal((Value *) object));
2395 			break;
2396 		case OBJECT_TSDICTIONARY:
2397 			if (!pg_ts_dict_ownercheck(address.objectId, roleid))
2398 				aclcheck_error(ACLCHECK_NOT_OWNER, objtype,
2399 							   NameListToString(castNode(List, object)));
2400 			break;
2401 		case OBJECT_TSCONFIGURATION:
2402 			if (!pg_ts_config_ownercheck(address.objectId, roleid))
2403 				aclcheck_error(ACLCHECK_NOT_OWNER, objtype,
2404 							   NameListToString(castNode(List, object)));
2405 			break;
2406 		case OBJECT_ROLE:
2407 
2408 			/*
2409 			 * We treat roles as being "owned" by those with CREATEROLE priv,
2410 			 * except that superusers are only owned by superusers.
2411 			 */
2412 			if (superuser_arg(address.objectId))
2413 			{
2414 				if (!superuser_arg(roleid))
2415 					ereport(ERROR,
2416 							(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2417 							 errmsg("must be superuser")));
2418 			}
2419 			else
2420 			{
2421 				if (!has_createrole_privilege(roleid))
2422 					ereport(ERROR,
2423 							(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2424 							 errmsg("must have CREATEROLE privilege")));
2425 			}
2426 			break;
2427 		case OBJECT_TSPARSER:
2428 		case OBJECT_TSTEMPLATE:
2429 		case OBJECT_ACCESS_METHOD:
2430 			/* We treat these object types as being owned by superusers */
2431 			if (!superuser_arg(roleid))
2432 				ereport(ERROR,
2433 						(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2434 						 errmsg("must be superuser")));
2435 			break;
2436 		case OBJECT_STATISTIC_EXT:
2437 			if (!pg_statistics_object_ownercheck(address.objectId, roleid))
2438 				aclcheck_error(ACLCHECK_NOT_OWNER, objtype,
2439 							   NameListToString(castNode(List, object)));
2440 			break;
2441 		default:
2442 			elog(ERROR, "unrecognized object type: %d",
2443 				 (int) objtype);
2444 	}
2445 }
2446 
2447 /*
2448  * get_object_namespace
2449  *
2450  * Find the schema containing the specified object.  For non-schema objects,
2451  * this function returns InvalidOid.
2452  */
2453 Oid
2454 get_object_namespace(const ObjectAddress *address)
2455 {
2456 	int			cache;
2457 	HeapTuple	tuple;
2458 	bool		isnull;
2459 	Oid			oid;
2460 	const ObjectPropertyType *property;
2461 
2462 	/* If not owned by a namespace, just return InvalidOid. */
2463 	property = get_object_property_data(address->classId);
2464 	if (property->attnum_namespace == InvalidAttrNumber)
2465 		return InvalidOid;
2466 
2467 	/* Currently, we can only handle object types with system caches. */
2468 	cache = property->oid_catcache_id;
2469 	Assert(cache != -1);
2470 
2471 	/* Fetch tuple from syscache and extract namespace attribute. */
2472 	tuple = SearchSysCache1(cache, ObjectIdGetDatum(address->objectId));
2473 	if (!HeapTupleIsValid(tuple))
2474 		elog(ERROR, "cache lookup failed for cache %d oid %u",
2475 			 cache, address->objectId);
2476 	oid = DatumGetObjectId(SysCacheGetAttr(cache,
2477 										   tuple,
2478 										   property->attnum_namespace,
2479 										   &isnull));
2480 	Assert(!isnull);
2481 	ReleaseSysCache(tuple);
2482 
2483 	return oid;
2484 }
2485 
2486 /*
2487  * Return ObjectType for the given object type as given by
2488  * getObjectTypeDescription; if no valid ObjectType code exists, but it's a
2489  * possible output type from getObjectTypeDescription, return -1.
2490  * Otherwise, an error is thrown.
2491  */
2492 int
2493 read_objtype_from_string(const char *objtype)
2494 {
2495 	int			i;
2496 
2497 	for (i = 0; i < lengthof(ObjectTypeMap); i++)
2498 	{
2499 		if (strcmp(ObjectTypeMap[i].tm_name, objtype) == 0)
2500 			return ObjectTypeMap[i].tm_type;
2501 	}
2502 	ereport(ERROR,
2503 			(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2504 			 errmsg("unrecognized object type \"%s\"", objtype)));
2505 
2506 	return -1;					/* keep compiler quiet */
2507 }
2508 
2509 /*
2510  * Interfaces to reference fields of ObjectPropertyType
2511  */
2512 Oid
2513 get_object_oid_index(Oid class_id)
2514 {
2515 	const ObjectPropertyType *prop = get_object_property_data(class_id);
2516 
2517 	return prop->oid_index_oid;
2518 }
2519 
2520 int
2521 get_object_catcache_oid(Oid class_id)
2522 {
2523 	const ObjectPropertyType *prop = get_object_property_data(class_id);
2524 
2525 	return prop->oid_catcache_id;
2526 }
2527 
2528 int
2529 get_object_catcache_name(Oid class_id)
2530 {
2531 	const ObjectPropertyType *prop = get_object_property_data(class_id);
2532 
2533 	return prop->name_catcache_id;
2534 }
2535 
2536 AttrNumber
2537 get_object_attnum_name(Oid class_id)
2538 {
2539 	const ObjectPropertyType *prop = get_object_property_data(class_id);
2540 
2541 	return prop->attnum_name;
2542 }
2543 
2544 AttrNumber
2545 get_object_attnum_namespace(Oid class_id)
2546 {
2547 	const ObjectPropertyType *prop = get_object_property_data(class_id);
2548 
2549 	return prop->attnum_namespace;
2550 }
2551 
2552 AttrNumber
2553 get_object_attnum_owner(Oid class_id)
2554 {
2555 	const ObjectPropertyType *prop = get_object_property_data(class_id);
2556 
2557 	return prop->attnum_owner;
2558 }
2559 
2560 AttrNumber
2561 get_object_attnum_acl(Oid class_id)
2562 {
2563 	const ObjectPropertyType *prop = get_object_property_data(class_id);
2564 
2565 	return prop->attnum_acl;
2566 }
2567 
2568 /*
2569  * get_object_type
2570  *
2571  * Return the object type associated with a given object.  This routine
2572  * is primarily used to determine the object type to mention in ACL check
2573  * error messages, so it's desirable for it to avoid failing.
2574  */
2575 ObjectType
2576 get_object_type(Oid class_id, Oid object_id)
2577 {
2578 	const ObjectPropertyType *prop = get_object_property_data(class_id);
2579 
2580 	if (prop->objtype == OBJECT_TABLE)
2581 	{
2582 		/*
2583 		 * If the property data says it's a table, dig a little deeper to get
2584 		 * the real relation kind, so that callers can produce more precise
2585 		 * error messages.
2586 		 */
2587 		return get_relkind_objtype(get_rel_relkind(object_id));
2588 	}
2589 	else
2590 		return prop->objtype;
2591 }
2592 
2593 bool
2594 get_object_namensp_unique(Oid class_id)
2595 {
2596 	const ObjectPropertyType *prop = get_object_property_data(class_id);
2597 
2598 	return prop->is_nsp_name_unique;
2599 }
2600 
2601 /*
2602  * Return whether we have useful data for the given object class in the
2603  * ObjectProperty table.
2604  */
2605 bool
2606 is_objectclass_supported(Oid class_id)
2607 {
2608 	int			index;
2609 
2610 	for (index = 0; index < lengthof(ObjectProperty); index++)
2611 	{
2612 		if (ObjectProperty[index].class_oid == class_id)
2613 			return true;
2614 	}
2615 
2616 	return false;
2617 }
2618 
2619 /*
2620  * Find ObjectProperty structure by class_id.
2621  */
2622 static const ObjectPropertyType *
2623 get_object_property_data(Oid class_id)
2624 {
2625 	static const ObjectPropertyType *prop_last = NULL;
2626 	int			index;
2627 
2628 	/*
2629 	 * A shortcut to speed up multiple consecutive lookups of a particular
2630 	 * object class.
2631 	 */
2632 	if (prop_last && prop_last->class_oid == class_id)
2633 		return prop_last;
2634 
2635 	for (index = 0; index < lengthof(ObjectProperty); index++)
2636 	{
2637 		if (ObjectProperty[index].class_oid == class_id)
2638 		{
2639 			prop_last = &ObjectProperty[index];
2640 			return &ObjectProperty[index];
2641 		}
2642 	}
2643 
2644 	ereport(ERROR,
2645 			(errmsg_internal("unrecognized class ID: %u", class_id)));
2646 
2647 	return NULL;				/* keep MSC compiler happy */
2648 }
2649 
2650 /*
2651  * Return a copy of the tuple for the object with the given object OID, from
2652  * the given catalog (which must have been opened by the caller and suitably
2653  * locked).  NULL is returned if the OID is not found.
2654  *
2655  * We try a syscache first, if available.
2656  */
2657 HeapTuple
2658 get_catalog_object_by_oid(Relation catalog, Oid objectId)
2659 {
2660 	HeapTuple	tuple;
2661 	Oid			classId = RelationGetRelid(catalog);
2662 	int			oidCacheId = get_object_catcache_oid(classId);
2663 
2664 	if (oidCacheId > 0)
2665 	{
2666 		tuple = SearchSysCacheCopy1(oidCacheId, ObjectIdGetDatum(objectId));
2667 		if (!HeapTupleIsValid(tuple))	/* should not happen */
2668 			return NULL;
2669 	}
2670 	else
2671 	{
2672 		Oid			oidIndexId = get_object_oid_index(classId);
2673 		SysScanDesc scan;
2674 		ScanKeyData skey;
2675 
2676 		Assert(OidIsValid(oidIndexId));
2677 
2678 		ScanKeyInit(&skey,
2679 					ObjectIdAttributeNumber,
2680 					BTEqualStrategyNumber, F_OIDEQ,
2681 					ObjectIdGetDatum(objectId));
2682 
2683 		scan = systable_beginscan(catalog, oidIndexId, true,
2684 								  NULL, 1, &skey);
2685 		tuple = systable_getnext(scan);
2686 		if (!HeapTupleIsValid(tuple))
2687 		{
2688 			systable_endscan(scan);
2689 			return NULL;
2690 		}
2691 		tuple = heap_copytuple(tuple);
2692 
2693 		systable_endscan(scan);
2694 	}
2695 
2696 	return tuple;
2697 }
2698 
2699 /*
2700  * getObjectDescription: build an object description for messages
2701  *
2702  * The result is a palloc'd string.
2703  */
2704 char *
2705 getObjectDescription(const ObjectAddress *object)
2706 {
2707 	StringInfoData buffer;
2708 
2709 	initStringInfo(&buffer);
2710 
2711 	switch (getObjectClass(object))
2712 	{
2713 		case OCLASS_CLASS:
2714 			if (object->objectSubId == 0)
2715 				getRelationDescription(&buffer, object->objectId);
2716 			else
2717 			{
2718 				/* column, not whole relation */
2719 				StringInfoData rel;
2720 
2721 				initStringInfo(&rel);
2722 				getRelationDescription(&rel, object->objectId);
2723 				/* translator: second %s is, e.g., "table %s" */
2724 				appendStringInfo(&buffer, _("column %s of %s"),
2725 								 get_attname(object->objectId,
2726 											 object->objectSubId,
2727 											 false),
2728 								 rel.data);
2729 				pfree(rel.data);
2730 			}
2731 			break;
2732 
2733 		case OCLASS_PROC:
2734 			appendStringInfo(&buffer, _("function %s"),
2735 							 format_procedure(object->objectId));
2736 			break;
2737 
2738 		case OCLASS_TYPE:
2739 			appendStringInfo(&buffer, _("type %s"),
2740 							 format_type_be(object->objectId));
2741 			break;
2742 
2743 		case OCLASS_CAST:
2744 			{
2745 				Relation	castDesc;
2746 				ScanKeyData skey[1];
2747 				SysScanDesc rcscan;
2748 				HeapTuple	tup;
2749 				Form_pg_cast castForm;
2750 
2751 				castDesc = heap_open(CastRelationId, AccessShareLock);
2752 
2753 				ScanKeyInit(&skey[0],
2754 							ObjectIdAttributeNumber,
2755 							BTEqualStrategyNumber, F_OIDEQ,
2756 							ObjectIdGetDatum(object->objectId));
2757 
2758 				rcscan = systable_beginscan(castDesc, CastOidIndexId, true,
2759 											NULL, 1, skey);
2760 
2761 				tup = systable_getnext(rcscan);
2762 
2763 				if (!HeapTupleIsValid(tup))
2764 					elog(ERROR, "could not find tuple for cast %u",
2765 						 object->objectId);
2766 
2767 				castForm = (Form_pg_cast) GETSTRUCT(tup);
2768 
2769 				appendStringInfo(&buffer, _("cast from %s to %s"),
2770 								 format_type_be(castForm->castsource),
2771 								 format_type_be(castForm->casttarget));
2772 
2773 				systable_endscan(rcscan);
2774 				heap_close(castDesc, AccessShareLock);
2775 				break;
2776 			}
2777 
2778 		case OCLASS_COLLATION:
2779 			{
2780 				HeapTuple	collTup;
2781 				Form_pg_collation coll;
2782 				char	   *nspname;
2783 
2784 				collTup = SearchSysCache1(COLLOID,
2785 										  ObjectIdGetDatum(object->objectId));
2786 				if (!HeapTupleIsValid(collTup))
2787 					elog(ERROR, "cache lookup failed for collation %u",
2788 						 object->objectId);
2789 				coll = (Form_pg_collation) GETSTRUCT(collTup);
2790 
2791 				/* Qualify the name if not visible in search path */
2792 				if (CollationIsVisible(object->objectId))
2793 					nspname = NULL;
2794 				else
2795 					nspname = get_namespace_name(coll->collnamespace);
2796 
2797 				appendStringInfo(&buffer, _("collation %s"),
2798 								 quote_qualified_identifier(nspname,
2799 															NameStr(coll->collname)));
2800 				ReleaseSysCache(collTup);
2801 				break;
2802 			}
2803 
2804 		case OCLASS_CONSTRAINT:
2805 			{
2806 				HeapTuple	conTup;
2807 				Form_pg_constraint con;
2808 
2809 				conTup = SearchSysCache1(CONSTROID,
2810 										 ObjectIdGetDatum(object->objectId));
2811 				if (!HeapTupleIsValid(conTup))
2812 					elog(ERROR, "cache lookup failed for constraint %u",
2813 						 object->objectId);
2814 				con = (Form_pg_constraint) GETSTRUCT(conTup);
2815 
2816 				if (OidIsValid(con->conrelid))
2817 				{
2818 					StringInfoData rel;
2819 
2820 					initStringInfo(&rel);
2821 					getRelationDescription(&rel, con->conrelid);
2822 					/* translator: second %s is, e.g., "table %s" */
2823 					appendStringInfo(&buffer, _("constraint %s on %s"),
2824 									 NameStr(con->conname), rel.data);
2825 					pfree(rel.data);
2826 				}
2827 				else
2828 				{
2829 					appendStringInfo(&buffer, _("constraint %s"),
2830 									 NameStr(con->conname));
2831 				}
2832 
2833 				ReleaseSysCache(conTup);
2834 				break;
2835 			}
2836 
2837 		case OCLASS_CONVERSION:
2838 			{
2839 				HeapTuple	conTup;
2840 				Form_pg_conversion conv;
2841 				char	   *nspname;
2842 
2843 				conTup = SearchSysCache1(CONVOID,
2844 										 ObjectIdGetDatum(object->objectId));
2845 				if (!HeapTupleIsValid(conTup))
2846 					elog(ERROR, "cache lookup failed for conversion %u",
2847 						 object->objectId);
2848 				conv = (Form_pg_conversion) GETSTRUCT(conTup);
2849 
2850 				/* Qualify the name if not visible in search path */
2851 				if (ConversionIsVisible(object->objectId))
2852 					nspname = NULL;
2853 				else
2854 					nspname = get_namespace_name(conv->connamespace);
2855 
2856 				appendStringInfo(&buffer, _("conversion %s"),
2857 								 quote_qualified_identifier(nspname,
2858 															NameStr(conv->conname)));
2859 				ReleaseSysCache(conTup);
2860 				break;
2861 			}
2862 
2863 		case OCLASS_DEFAULT:
2864 			{
2865 				Relation	attrdefDesc;
2866 				ScanKeyData skey[1];
2867 				SysScanDesc adscan;
2868 				HeapTuple	tup;
2869 				Form_pg_attrdef attrdef;
2870 				ObjectAddress colobject;
2871 
2872 				attrdefDesc = heap_open(AttrDefaultRelationId, AccessShareLock);
2873 
2874 				ScanKeyInit(&skey[0],
2875 							ObjectIdAttributeNumber,
2876 							BTEqualStrategyNumber, F_OIDEQ,
2877 							ObjectIdGetDatum(object->objectId));
2878 
2879 				adscan = systable_beginscan(attrdefDesc, AttrDefaultOidIndexId,
2880 											true, NULL, 1, skey);
2881 
2882 				tup = systable_getnext(adscan);
2883 
2884 				if (!HeapTupleIsValid(tup))
2885 					elog(ERROR, "could not find tuple for attrdef %u",
2886 						 object->objectId);
2887 
2888 				attrdef = (Form_pg_attrdef) GETSTRUCT(tup);
2889 
2890 				colobject.classId = RelationRelationId;
2891 				colobject.objectId = attrdef->adrelid;
2892 				colobject.objectSubId = attrdef->adnum;
2893 
2894 				/* translator: %s is typically "column %s of table %s" */
2895 				appendStringInfo(&buffer, _("default value for %s"),
2896 								 getObjectDescription(&colobject));
2897 
2898 				systable_endscan(adscan);
2899 				heap_close(attrdefDesc, AccessShareLock);
2900 				break;
2901 			}
2902 
2903 		case OCLASS_LANGUAGE:
2904 			appendStringInfo(&buffer, _("language %s"),
2905 							 get_language_name(object->objectId, false));
2906 			break;
2907 
2908 		case OCLASS_LARGEOBJECT:
2909 			appendStringInfo(&buffer, _("large object %u"),
2910 							 object->objectId);
2911 			break;
2912 
2913 		case OCLASS_OPERATOR:
2914 			appendStringInfo(&buffer, _("operator %s"),
2915 							 format_operator(object->objectId));
2916 			break;
2917 
2918 		case OCLASS_OPCLASS:
2919 			{
2920 				HeapTuple	opcTup;
2921 				Form_pg_opclass opcForm;
2922 				HeapTuple	amTup;
2923 				Form_pg_am	amForm;
2924 				char	   *nspname;
2925 
2926 				opcTup = SearchSysCache1(CLAOID,
2927 										 ObjectIdGetDatum(object->objectId));
2928 				if (!HeapTupleIsValid(opcTup))
2929 					elog(ERROR, "cache lookup failed for opclass %u",
2930 						 object->objectId);
2931 				opcForm = (Form_pg_opclass) GETSTRUCT(opcTup);
2932 
2933 				amTup = SearchSysCache1(AMOID,
2934 										ObjectIdGetDatum(opcForm->opcmethod));
2935 				if (!HeapTupleIsValid(amTup))
2936 					elog(ERROR, "cache lookup failed for access method %u",
2937 						 opcForm->opcmethod);
2938 				amForm = (Form_pg_am) GETSTRUCT(amTup);
2939 
2940 				/* Qualify the name if not visible in search path */
2941 				if (OpclassIsVisible(object->objectId))
2942 					nspname = NULL;
2943 				else
2944 					nspname = get_namespace_name(opcForm->opcnamespace);
2945 
2946 				appendStringInfo(&buffer, _("operator class %s for access method %s"),
2947 								 quote_qualified_identifier(nspname,
2948 															NameStr(opcForm->opcname)),
2949 								 NameStr(amForm->amname));
2950 
2951 				ReleaseSysCache(amTup);
2952 				ReleaseSysCache(opcTup);
2953 				break;
2954 			}
2955 
2956 		case OCLASS_OPFAMILY:
2957 			getOpFamilyDescription(&buffer, object->objectId);
2958 			break;
2959 
2960 		case OCLASS_AM:
2961 			{
2962 				HeapTuple	tup;
2963 
2964 				tup = SearchSysCache1(AMOID,
2965 									  ObjectIdGetDatum(object->objectId));
2966 				if (!HeapTupleIsValid(tup))
2967 					elog(ERROR, "cache lookup failed for access method %u",
2968 						 object->objectId);
2969 				appendStringInfo(&buffer, _("access method %s"),
2970 								 NameStr(((Form_pg_am) GETSTRUCT(tup))->amname));
2971 				ReleaseSysCache(tup);
2972 				break;
2973 			}
2974 
2975 		case OCLASS_AMOP:
2976 			{
2977 				Relation	amopDesc;
2978 				HeapTuple	tup;
2979 				ScanKeyData skey[1];
2980 				SysScanDesc amscan;
2981 				Form_pg_amop amopForm;
2982 				StringInfoData opfam;
2983 
2984 				amopDesc = heap_open(AccessMethodOperatorRelationId,
2985 									 AccessShareLock);
2986 
2987 				ScanKeyInit(&skey[0],
2988 							ObjectIdAttributeNumber,
2989 							BTEqualStrategyNumber, F_OIDEQ,
2990 							ObjectIdGetDatum(object->objectId));
2991 
2992 				amscan = systable_beginscan(amopDesc, AccessMethodOperatorOidIndexId, true,
2993 											NULL, 1, skey);
2994 
2995 				tup = systable_getnext(amscan);
2996 
2997 				if (!HeapTupleIsValid(tup))
2998 					elog(ERROR, "could not find tuple for amop entry %u",
2999 						 object->objectId);
3000 
3001 				amopForm = (Form_pg_amop) GETSTRUCT(tup);
3002 
3003 				initStringInfo(&opfam);
3004 				getOpFamilyDescription(&opfam, amopForm->amopfamily);
3005 
3006 				/*------
3007 				   translator: %d is the operator strategy (a number), the
3008 				   first two %s's are data type names, the third %s is the
3009 				   description of the operator family, and the last %s is the
3010 				   textual form of the operator with arguments.  */
3011 				appendStringInfo(&buffer, _("operator %d (%s, %s) of %s: %s"),
3012 								 amopForm->amopstrategy,
3013 								 format_type_be(amopForm->amoplefttype),
3014 								 format_type_be(amopForm->amoprighttype),
3015 								 opfam.data,
3016 								 format_operator(amopForm->amopopr));
3017 
3018 				pfree(opfam.data);
3019 
3020 				systable_endscan(amscan);
3021 				heap_close(amopDesc, AccessShareLock);
3022 				break;
3023 			}
3024 
3025 		case OCLASS_AMPROC:
3026 			{
3027 				Relation	amprocDesc;
3028 				ScanKeyData skey[1];
3029 				SysScanDesc amscan;
3030 				HeapTuple	tup;
3031 				Form_pg_amproc amprocForm;
3032 				StringInfoData opfam;
3033 
3034 				amprocDesc = heap_open(AccessMethodProcedureRelationId,
3035 									   AccessShareLock);
3036 
3037 				ScanKeyInit(&skey[0],
3038 							ObjectIdAttributeNumber,
3039 							BTEqualStrategyNumber, F_OIDEQ,
3040 							ObjectIdGetDatum(object->objectId));
3041 
3042 				amscan = systable_beginscan(amprocDesc, AccessMethodProcedureOidIndexId, true,
3043 											NULL, 1, skey);
3044 
3045 				tup = systable_getnext(amscan);
3046 
3047 				if (!HeapTupleIsValid(tup))
3048 					elog(ERROR, "could not find tuple for amproc entry %u",
3049 						 object->objectId);
3050 
3051 				amprocForm = (Form_pg_amproc) GETSTRUCT(tup);
3052 
3053 				initStringInfo(&opfam);
3054 				getOpFamilyDescription(&opfam, amprocForm->amprocfamily);
3055 
3056 				/*------
3057 				   translator: %d is the function number, the first two %s's
3058 				   are data type names, the third %s is the description of the
3059 				   operator family, and the last %s is the textual form of the
3060 				   function with arguments.  */
3061 				appendStringInfo(&buffer, _("function %d (%s, %s) of %s: %s"),
3062 								 amprocForm->amprocnum,
3063 								 format_type_be(amprocForm->amproclefttype),
3064 								 format_type_be(amprocForm->amprocrighttype),
3065 								 opfam.data,
3066 								 format_procedure(amprocForm->amproc));
3067 
3068 				pfree(opfam.data);
3069 
3070 				systable_endscan(amscan);
3071 				heap_close(amprocDesc, AccessShareLock);
3072 				break;
3073 			}
3074 
3075 		case OCLASS_REWRITE:
3076 			{
3077 				Relation	ruleDesc;
3078 				ScanKeyData skey[1];
3079 				SysScanDesc rcscan;
3080 				HeapTuple	tup;
3081 				Form_pg_rewrite rule;
3082 				StringInfoData rel;
3083 
3084 				ruleDesc = heap_open(RewriteRelationId, AccessShareLock);
3085 
3086 				ScanKeyInit(&skey[0],
3087 							ObjectIdAttributeNumber,
3088 							BTEqualStrategyNumber, F_OIDEQ,
3089 							ObjectIdGetDatum(object->objectId));
3090 
3091 				rcscan = systable_beginscan(ruleDesc, RewriteOidIndexId, true,
3092 											NULL, 1, skey);
3093 
3094 				tup = systable_getnext(rcscan);
3095 
3096 				if (!HeapTupleIsValid(tup))
3097 					elog(ERROR, "could not find tuple for rule %u",
3098 						 object->objectId);
3099 				rule = (Form_pg_rewrite) GETSTRUCT(tup);
3100 
3101 				initStringInfo(&rel);
3102 				getRelationDescription(&rel, rule->ev_class);
3103 
3104 				/* translator: second %s is, e.g., "table %s" */
3105 				appendStringInfo(&buffer, _("rule %s on %s"),
3106 								 NameStr(rule->rulename), rel.data);
3107 				pfree(rel.data);
3108 				systable_endscan(rcscan);
3109 				heap_close(ruleDesc, AccessShareLock);
3110 				break;
3111 			}
3112 
3113 		case OCLASS_TRIGGER:
3114 			{
3115 				Relation	trigDesc;
3116 				ScanKeyData skey[1];
3117 				SysScanDesc tgscan;
3118 				HeapTuple	tup;
3119 				Form_pg_trigger trig;
3120 				StringInfoData rel;
3121 
3122 				trigDesc = heap_open(TriggerRelationId, AccessShareLock);
3123 
3124 				ScanKeyInit(&skey[0],
3125 							ObjectIdAttributeNumber,
3126 							BTEqualStrategyNumber, F_OIDEQ,
3127 							ObjectIdGetDatum(object->objectId));
3128 
3129 				tgscan = systable_beginscan(trigDesc, TriggerOidIndexId, true,
3130 											NULL, 1, skey);
3131 
3132 				tup = systable_getnext(tgscan);
3133 
3134 				if (!HeapTupleIsValid(tup))
3135 					elog(ERROR, "could not find tuple for trigger %u",
3136 						 object->objectId);
3137 				trig = (Form_pg_trigger) GETSTRUCT(tup);
3138 
3139 				initStringInfo(&rel);
3140 				getRelationDescription(&rel, trig->tgrelid);
3141 
3142 				/* translator: second %s is, e.g., "table %s" */
3143 				appendStringInfo(&buffer, _("trigger %s on %s"),
3144 								 NameStr(trig->tgname), rel.data);
3145 				pfree(rel.data);
3146 				systable_endscan(tgscan);
3147 				heap_close(trigDesc, AccessShareLock);
3148 				break;
3149 			}
3150 
3151 		case OCLASS_SCHEMA:
3152 			{
3153 				char	   *nspname;
3154 
3155 				nspname = get_namespace_name(object->objectId);
3156 				if (!nspname)
3157 					elog(ERROR, "cache lookup failed for namespace %u",
3158 						 object->objectId);
3159 				appendStringInfo(&buffer, _("schema %s"), nspname);
3160 				break;
3161 			}
3162 
3163 		case OCLASS_STATISTIC_EXT:
3164 			{
3165 				HeapTuple	stxTup;
3166 				Form_pg_statistic_ext stxForm;
3167 				char	   *nspname;
3168 
3169 				stxTup = SearchSysCache1(STATEXTOID,
3170 										 ObjectIdGetDatum(object->objectId));
3171 				if (!HeapTupleIsValid(stxTup))
3172 					elog(ERROR, "could not find tuple for statistics object %u",
3173 						 object->objectId);
3174 				stxForm = (Form_pg_statistic_ext) GETSTRUCT(stxTup);
3175 
3176 				/* Qualify the name if not visible in search path */
3177 				if (StatisticsObjIsVisible(object->objectId))
3178 					nspname = NULL;
3179 				else
3180 					nspname = get_namespace_name(stxForm->stxnamespace);
3181 
3182 				appendStringInfo(&buffer, _("statistics object %s"),
3183 								 quote_qualified_identifier(nspname,
3184 															NameStr(stxForm->stxname)));
3185 
3186 				ReleaseSysCache(stxTup);
3187 				break;
3188 			}
3189 
3190 		case OCLASS_TSPARSER:
3191 			{
3192 				HeapTuple	tup;
3193 				Form_pg_ts_parser prsForm;
3194 				char	   *nspname;
3195 
3196 				tup = SearchSysCache1(TSPARSEROID,
3197 									  ObjectIdGetDatum(object->objectId));
3198 				if (!HeapTupleIsValid(tup))
3199 					elog(ERROR, "cache lookup failed for text search parser %u",
3200 						 object->objectId);
3201 				prsForm = (Form_pg_ts_parser) GETSTRUCT(tup);
3202 
3203 				/* Qualify the name if not visible in search path */
3204 				if (TSParserIsVisible(object->objectId))
3205 					nspname = NULL;
3206 				else
3207 					nspname = get_namespace_name(prsForm->prsnamespace);
3208 
3209 				appendStringInfo(&buffer, _("text search parser %s"),
3210 								 quote_qualified_identifier(nspname,
3211 															NameStr(prsForm->prsname)));
3212 				ReleaseSysCache(tup);
3213 				break;
3214 			}
3215 
3216 		case OCLASS_TSDICT:
3217 			{
3218 				HeapTuple	tup;
3219 				Form_pg_ts_dict dictForm;
3220 				char	   *nspname;
3221 
3222 				tup = SearchSysCache1(TSDICTOID,
3223 									  ObjectIdGetDatum(object->objectId));
3224 				if (!HeapTupleIsValid(tup))
3225 					elog(ERROR, "cache lookup failed for text search dictionary %u",
3226 						 object->objectId);
3227 				dictForm = (Form_pg_ts_dict) GETSTRUCT(tup);
3228 
3229 				/* Qualify the name if not visible in search path */
3230 				if (TSDictionaryIsVisible(object->objectId))
3231 					nspname = NULL;
3232 				else
3233 					nspname = get_namespace_name(dictForm->dictnamespace);
3234 
3235 				appendStringInfo(&buffer, _("text search dictionary %s"),
3236 								 quote_qualified_identifier(nspname,
3237 															NameStr(dictForm->dictname)));
3238 				ReleaseSysCache(tup);
3239 				break;
3240 			}
3241 
3242 		case OCLASS_TSTEMPLATE:
3243 			{
3244 				HeapTuple	tup;
3245 				Form_pg_ts_template tmplForm;
3246 				char	   *nspname;
3247 
3248 				tup = SearchSysCache1(TSTEMPLATEOID,
3249 									  ObjectIdGetDatum(object->objectId));
3250 				if (!HeapTupleIsValid(tup))
3251 					elog(ERROR, "cache lookup failed for text search template %u",
3252 						 object->objectId);
3253 				tmplForm = (Form_pg_ts_template) GETSTRUCT(tup);
3254 
3255 				/* Qualify the name if not visible in search path */
3256 				if (TSTemplateIsVisible(object->objectId))
3257 					nspname = NULL;
3258 				else
3259 					nspname = get_namespace_name(tmplForm->tmplnamespace);
3260 
3261 				appendStringInfo(&buffer, _("text search template %s"),
3262 								 quote_qualified_identifier(nspname,
3263 															NameStr(tmplForm->tmplname)));
3264 				ReleaseSysCache(tup);
3265 				break;
3266 			}
3267 
3268 		case OCLASS_TSCONFIG:
3269 			{
3270 				HeapTuple	tup;
3271 				Form_pg_ts_config cfgForm;
3272 				char	   *nspname;
3273 
3274 				tup = SearchSysCache1(TSCONFIGOID,
3275 									  ObjectIdGetDatum(object->objectId));
3276 				if (!HeapTupleIsValid(tup))
3277 					elog(ERROR, "cache lookup failed for text search configuration %u",
3278 						 object->objectId);
3279 				cfgForm = (Form_pg_ts_config) GETSTRUCT(tup);
3280 
3281 				/* Qualify the name if not visible in search path */
3282 				if (TSConfigIsVisible(object->objectId))
3283 					nspname = NULL;
3284 				else
3285 					nspname = get_namespace_name(cfgForm->cfgnamespace);
3286 
3287 				appendStringInfo(&buffer, _("text search configuration %s"),
3288 								 quote_qualified_identifier(nspname,
3289 															NameStr(cfgForm->cfgname)));
3290 				ReleaseSysCache(tup);
3291 				break;
3292 			}
3293 
3294 		case OCLASS_ROLE:
3295 			{
3296 				appendStringInfo(&buffer, _("role %s"),
3297 								 GetUserNameFromId(object->objectId, false));
3298 				break;
3299 			}
3300 
3301 		case OCLASS_DATABASE:
3302 			{
3303 				char	   *datname;
3304 
3305 				datname = get_database_name(object->objectId);
3306 				if (!datname)
3307 					elog(ERROR, "cache lookup failed for database %u",
3308 						 object->objectId);
3309 				appendStringInfo(&buffer, _("database %s"), datname);
3310 				break;
3311 			}
3312 
3313 		case OCLASS_TBLSPACE:
3314 			{
3315 				char	   *tblspace;
3316 
3317 				tblspace = get_tablespace_name(object->objectId);
3318 				if (!tblspace)
3319 					elog(ERROR, "cache lookup failed for tablespace %u",
3320 						 object->objectId);
3321 				appendStringInfo(&buffer, _("tablespace %s"), tblspace);
3322 				break;
3323 			}
3324 
3325 		case OCLASS_FDW:
3326 			{
3327 				ForeignDataWrapper *fdw;
3328 
3329 				fdw = GetForeignDataWrapper(object->objectId);
3330 				appendStringInfo(&buffer, _("foreign-data wrapper %s"), fdw->fdwname);
3331 				break;
3332 			}
3333 
3334 		case OCLASS_FOREIGN_SERVER:
3335 			{
3336 				ForeignServer *srv;
3337 
3338 				srv = GetForeignServer(object->objectId);
3339 				appendStringInfo(&buffer, _("server %s"), srv->servername);
3340 				break;
3341 			}
3342 
3343 		case OCLASS_USER_MAPPING:
3344 			{
3345 				HeapTuple	tup;
3346 				Oid			useid;
3347 				char	   *usename;
3348 				Form_pg_user_mapping umform;
3349 				ForeignServer *srv;
3350 
3351 				tup = SearchSysCache1(USERMAPPINGOID,
3352 									  ObjectIdGetDatum(object->objectId));
3353 				if (!HeapTupleIsValid(tup))
3354 					elog(ERROR, "cache lookup failed for user mapping %u",
3355 						 object->objectId);
3356 				umform = (Form_pg_user_mapping) GETSTRUCT(tup);
3357 				useid = umform->umuser;
3358 				srv = GetForeignServer(umform->umserver);
3359 
3360 				ReleaseSysCache(tup);
3361 
3362 				if (OidIsValid(useid))
3363 					usename = GetUserNameFromId(useid, false);
3364 				else
3365 					usename = "public";
3366 
3367 				appendStringInfo(&buffer, _("user mapping for %s on server %s"), usename,
3368 								 srv->servername);
3369 				break;
3370 			}
3371 
3372 		case OCLASS_DEFACL:
3373 			{
3374 				Relation	defaclrel;
3375 				ScanKeyData skey[1];
3376 				SysScanDesc rcscan;
3377 				HeapTuple	tup;
3378 				Form_pg_default_acl defacl;
3379 				char	   *rolename;
3380 				char	   *nspname;
3381 
3382 				defaclrel = heap_open(DefaultAclRelationId, AccessShareLock);
3383 
3384 				ScanKeyInit(&skey[0],
3385 							ObjectIdAttributeNumber,
3386 							BTEqualStrategyNumber, F_OIDEQ,
3387 							ObjectIdGetDatum(object->objectId));
3388 
3389 				rcscan = systable_beginscan(defaclrel, DefaultAclOidIndexId,
3390 											true, NULL, 1, skey);
3391 
3392 				tup = systable_getnext(rcscan);
3393 
3394 				if (!HeapTupleIsValid(tup))
3395 					elog(ERROR, "could not find tuple for default ACL %u",
3396 						 object->objectId);
3397 
3398 				defacl = (Form_pg_default_acl) GETSTRUCT(tup);
3399 
3400 				rolename = GetUserNameFromId(defacl->defaclrole, false);
3401 
3402 				if (OidIsValid(defacl->defaclnamespace))
3403 					nspname = get_namespace_name(defacl->defaclnamespace);
3404 				else
3405 					nspname = NULL;
3406 
3407 				switch (defacl->defaclobjtype)
3408 				{
3409 					case DEFACLOBJ_RELATION:
3410 						if (nspname)
3411 							appendStringInfo(&buffer,
3412 											 _("default privileges on new relations belonging to role %s in schema %s"),
3413 											 rolename, nspname);
3414 						else
3415 							appendStringInfo(&buffer,
3416 											 _("default privileges on new relations belonging to role %s"),
3417 											 rolename);
3418 						break;
3419 					case DEFACLOBJ_SEQUENCE:
3420 						if (nspname)
3421 							appendStringInfo(&buffer,
3422 											 _("default privileges on new sequences belonging to role %s in schema %s"),
3423 											 rolename, nspname);
3424 						else
3425 							appendStringInfo(&buffer,
3426 											 _("default privileges on new sequences belonging to role %s"),
3427 											 rolename);
3428 						break;
3429 					case DEFACLOBJ_FUNCTION:
3430 						if (nspname)
3431 							appendStringInfo(&buffer,
3432 											 _("default privileges on new functions belonging to role %s in schema %s"),
3433 											 rolename, nspname);
3434 						else
3435 							appendStringInfo(&buffer,
3436 											 _("default privileges on new functions belonging to role %s"),
3437 											 rolename);
3438 						break;
3439 					case DEFACLOBJ_TYPE:
3440 						if (nspname)
3441 							appendStringInfo(&buffer,
3442 											 _("default privileges on new types belonging to role %s in schema %s"),
3443 											 rolename, nspname);
3444 						else
3445 							appendStringInfo(&buffer,
3446 											 _("default privileges on new types belonging to role %s"),
3447 											 rolename);
3448 						break;
3449 					case DEFACLOBJ_NAMESPACE:
3450 						Assert(!nspname);
3451 						appendStringInfo(&buffer,
3452 										 _("default privileges on new schemas belonging to role %s"),
3453 										 rolename);
3454 						break;
3455 					default:
3456 						/* shouldn't get here */
3457 						if (nspname)
3458 							appendStringInfo(&buffer,
3459 											 _("default privileges belonging to role %s in schema %s"),
3460 											 rolename, nspname);
3461 						else
3462 							appendStringInfo(&buffer,
3463 											 _("default privileges belonging to role %s"),
3464 											 rolename);
3465 						break;
3466 				}
3467 
3468 				systable_endscan(rcscan);
3469 				heap_close(defaclrel, AccessShareLock);
3470 				break;
3471 			}
3472 
3473 		case OCLASS_EXTENSION:
3474 			{
3475 				char	   *extname;
3476 
3477 				extname = get_extension_name(object->objectId);
3478 				if (!extname)
3479 					elog(ERROR, "cache lookup failed for extension %u",
3480 						 object->objectId);
3481 				appendStringInfo(&buffer, _("extension %s"), extname);
3482 				break;
3483 			}
3484 
3485 		case OCLASS_EVENT_TRIGGER:
3486 			{
3487 				HeapTuple	tup;
3488 
3489 				tup = SearchSysCache1(EVENTTRIGGEROID,
3490 									  ObjectIdGetDatum(object->objectId));
3491 				if (!HeapTupleIsValid(tup))
3492 					elog(ERROR, "cache lookup failed for event trigger %u",
3493 						 object->objectId);
3494 				appendStringInfo(&buffer, _("event trigger %s"),
3495 								 NameStr(((Form_pg_event_trigger) GETSTRUCT(tup))->evtname));
3496 				ReleaseSysCache(tup);
3497 				break;
3498 			}
3499 
3500 		case OCLASS_POLICY:
3501 			{
3502 				Relation	policy_rel;
3503 				ScanKeyData skey[1];
3504 				SysScanDesc sscan;
3505 				HeapTuple	tuple;
3506 				Form_pg_policy form_policy;
3507 				StringInfoData rel;
3508 
3509 				policy_rel = heap_open(PolicyRelationId, AccessShareLock);
3510 
3511 				ScanKeyInit(&skey[0],
3512 							ObjectIdAttributeNumber,
3513 							BTEqualStrategyNumber, F_OIDEQ,
3514 							ObjectIdGetDatum(object->objectId));
3515 
3516 				sscan = systable_beginscan(policy_rel, PolicyOidIndexId,
3517 										   true, NULL, 1, skey);
3518 
3519 				tuple = systable_getnext(sscan);
3520 
3521 				if (!HeapTupleIsValid(tuple))
3522 					elog(ERROR, "could not find tuple for policy %u",
3523 						 object->objectId);
3524 				form_policy = (Form_pg_policy) GETSTRUCT(tuple);
3525 
3526 				initStringInfo(&rel);
3527 				getRelationDescription(&rel, form_policy->polrelid);
3528 
3529 				/* translator: second %s is, e.g., "table %s" */
3530 				appendStringInfo(&buffer, _("policy %s on %s"),
3531 								 NameStr(form_policy->polname), rel.data);
3532 				pfree(rel.data);
3533 				systable_endscan(sscan);
3534 				heap_close(policy_rel, AccessShareLock);
3535 				break;
3536 			}
3537 
3538 		case OCLASS_PUBLICATION:
3539 			{
3540 				appendStringInfo(&buffer, _("publication %s"),
3541 								 get_publication_name(object->objectId));
3542 				break;
3543 			}
3544 
3545 		case OCLASS_PUBLICATION_REL:
3546 			{
3547 				HeapTuple	tup;
3548 				char	   *pubname;
3549 				Form_pg_publication_rel prform;
3550 				StringInfoData rel;
3551 
3552 				tup = SearchSysCache1(PUBLICATIONREL,
3553 									  ObjectIdGetDatum(object->objectId));
3554 				if (!HeapTupleIsValid(tup))
3555 					elog(ERROR, "cache lookup failed for publication table %u",
3556 						 object->objectId);
3557 
3558 				prform = (Form_pg_publication_rel) GETSTRUCT(tup);
3559 				pubname = get_publication_name(prform->prpubid);
3560 
3561 				initStringInfo(&rel);
3562 				getRelationDescription(&rel, prform->prrelid);
3563 
3564 				/* translator: first %s is, e.g., "table %s" */
3565 				appendStringInfo(&buffer, _("publication of %s in publication %s"),
3566 								 rel.data, pubname);
3567 				pfree(rel.data);
3568 				ReleaseSysCache(tup);
3569 				break;
3570 			}
3571 
3572 		case OCLASS_SUBSCRIPTION:
3573 			{
3574 				appendStringInfo(&buffer, _("subscription %s"),
3575 								 get_subscription_name(object->objectId));
3576 				break;
3577 			}
3578 
3579 		case OCLASS_TRANSFORM:
3580 			{
3581 				HeapTuple	trfTup;
3582 				Form_pg_transform trfForm;
3583 
3584 				trfTup = SearchSysCache1(TRFOID,
3585 										 ObjectIdGetDatum(object->objectId));
3586 				if (!HeapTupleIsValid(trfTup))
3587 					elog(ERROR, "could not find tuple for transform %u",
3588 						 object->objectId);
3589 
3590 				trfForm = (Form_pg_transform) GETSTRUCT(trfTup);
3591 
3592 				appendStringInfo(&buffer, _("transform for %s language %s"),
3593 								 format_type_be(trfForm->trftype),
3594 								 get_language_name(trfForm->trflang, false));
3595 
3596 				ReleaseSysCache(trfTup);
3597 				break;
3598 			}
3599 
3600 			/*
3601 			 * There's intentionally no default: case here; we want the
3602 			 * compiler to warn if a new OCLASS hasn't been handled above.
3603 			 */
3604 	}
3605 
3606 	return buffer.data;
3607 }
3608 
3609 /*
3610  * getObjectDescriptionOids: as above, except the object is specified by Oids
3611  */
3612 char *
3613 getObjectDescriptionOids(Oid classid, Oid objid)
3614 {
3615 	ObjectAddress address;
3616 
3617 	address.classId = classid;
3618 	address.objectId = objid;
3619 	address.objectSubId = 0;
3620 
3621 	return getObjectDescription(&address);
3622 }
3623 
3624 /*
3625  * subroutine for getObjectDescription: describe a relation
3626  *
3627  * The result is appended to "buffer".
3628  */
3629 static void
3630 getRelationDescription(StringInfo buffer, Oid relid)
3631 {
3632 	HeapTuple	relTup;
3633 	Form_pg_class relForm;
3634 	char	   *nspname;
3635 	char	   *relname;
3636 
3637 	relTup = SearchSysCache1(RELOID,
3638 							 ObjectIdGetDatum(relid));
3639 	if (!HeapTupleIsValid(relTup))
3640 		elog(ERROR, "cache lookup failed for relation %u", relid);
3641 	relForm = (Form_pg_class) GETSTRUCT(relTup);
3642 
3643 	/* Qualify the name if not visible in search path */
3644 	if (RelationIsVisible(relid))
3645 		nspname = NULL;
3646 	else
3647 		nspname = get_namespace_name(relForm->relnamespace);
3648 
3649 	relname = quote_qualified_identifier(nspname, NameStr(relForm->relname));
3650 
3651 	switch (relForm->relkind)
3652 	{
3653 		case RELKIND_RELATION:
3654 		case RELKIND_PARTITIONED_TABLE:
3655 			appendStringInfo(buffer, _("table %s"),
3656 							 relname);
3657 			break;
3658 		case RELKIND_INDEX:
3659 		case RELKIND_PARTITIONED_INDEX:
3660 			appendStringInfo(buffer, _("index %s"),
3661 							 relname);
3662 			break;
3663 		case RELKIND_SEQUENCE:
3664 			appendStringInfo(buffer, _("sequence %s"),
3665 							 relname);
3666 			break;
3667 		case RELKIND_TOASTVALUE:
3668 			appendStringInfo(buffer, _("toast table %s"),
3669 							 relname);
3670 			break;
3671 		case RELKIND_VIEW:
3672 			appendStringInfo(buffer, _("view %s"),
3673 							 relname);
3674 			break;
3675 		case RELKIND_MATVIEW:
3676 			appendStringInfo(buffer, _("materialized view %s"),
3677 							 relname);
3678 			break;
3679 		case RELKIND_COMPOSITE_TYPE:
3680 			appendStringInfo(buffer, _("composite type %s"),
3681 							 relname);
3682 			break;
3683 		case RELKIND_FOREIGN_TABLE:
3684 			appendStringInfo(buffer, _("foreign table %s"),
3685 							 relname);
3686 			break;
3687 		default:
3688 			/* shouldn't get here */
3689 			appendStringInfo(buffer, _("relation %s"),
3690 							 relname);
3691 			break;
3692 	}
3693 
3694 	ReleaseSysCache(relTup);
3695 }
3696 
3697 /*
3698  * subroutine for getObjectDescription: describe an operator family
3699  */
3700 static void
3701 getOpFamilyDescription(StringInfo buffer, Oid opfid)
3702 {
3703 	HeapTuple	opfTup;
3704 	Form_pg_opfamily opfForm;
3705 	HeapTuple	amTup;
3706 	Form_pg_am	amForm;
3707 	char	   *nspname;
3708 
3709 	opfTup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfid));
3710 	if (!HeapTupleIsValid(opfTup))
3711 		elog(ERROR, "cache lookup failed for opfamily %u", opfid);
3712 	opfForm = (Form_pg_opfamily) GETSTRUCT(opfTup);
3713 
3714 	amTup = SearchSysCache1(AMOID, ObjectIdGetDatum(opfForm->opfmethod));
3715 	if (!HeapTupleIsValid(amTup))
3716 		elog(ERROR, "cache lookup failed for access method %u",
3717 			 opfForm->opfmethod);
3718 	amForm = (Form_pg_am) GETSTRUCT(amTup);
3719 
3720 	/* Qualify the name if not visible in search path */
3721 	if (OpfamilyIsVisible(opfid))
3722 		nspname = NULL;
3723 	else
3724 		nspname = get_namespace_name(opfForm->opfnamespace);
3725 
3726 	appendStringInfo(buffer, _("operator family %s for access method %s"),
3727 					 quote_qualified_identifier(nspname,
3728 												NameStr(opfForm->opfname)),
3729 					 NameStr(amForm->amname));
3730 
3731 	ReleaseSysCache(amTup);
3732 	ReleaseSysCache(opfTup);
3733 }
3734 
3735 /*
3736  * SQL-level callable version of getObjectDescription
3737  */
3738 Datum
3739 pg_describe_object(PG_FUNCTION_ARGS)
3740 {
3741 	Oid			classid = PG_GETARG_OID(0);
3742 	Oid			objid = PG_GETARG_OID(1);
3743 	int32		objsubid = PG_GETARG_INT32(2);
3744 	char	   *description;
3745 	ObjectAddress address;
3746 
3747 	/* for "pinned" items in pg_depend, return null */
3748 	if (!OidIsValid(classid) && !OidIsValid(objid))
3749 		PG_RETURN_NULL();
3750 
3751 	address.classId = classid;
3752 	address.objectId = objid;
3753 	address.objectSubId = objsubid;
3754 
3755 	description = getObjectDescription(&address);
3756 	PG_RETURN_TEXT_P(cstring_to_text(description));
3757 }
3758 
3759 /*
3760  * SQL-level callable function to obtain object type + identity
3761  */
3762 Datum
3763 pg_identify_object(PG_FUNCTION_ARGS)
3764 {
3765 	Oid			classid = PG_GETARG_OID(0);
3766 	Oid			objid = PG_GETARG_OID(1);
3767 	int32		objsubid = PG_GETARG_INT32(2);
3768 	Oid			schema_oid = InvalidOid;
3769 	const char *objname = NULL;
3770 	ObjectAddress address;
3771 	Datum		values[4];
3772 	bool		nulls[4];
3773 	TupleDesc	tupdesc;
3774 	HeapTuple	htup;
3775 
3776 	address.classId = classid;
3777 	address.objectId = objid;
3778 	address.objectSubId = objsubid;
3779 
3780 	/*
3781 	 * Construct a tuple descriptor for the result row.  This must match this
3782 	 * function's pg_proc entry!
3783 	 */
3784 	tupdesc = CreateTemplateTupleDesc(4, false);
3785 	TupleDescInitEntry(tupdesc, (AttrNumber) 1, "type",
3786 					   TEXTOID, -1, 0);
3787 	TupleDescInitEntry(tupdesc, (AttrNumber) 2, "schema",
3788 					   TEXTOID, -1, 0);
3789 	TupleDescInitEntry(tupdesc, (AttrNumber) 3, "name",
3790 					   TEXTOID, -1, 0);
3791 	TupleDescInitEntry(tupdesc, (AttrNumber) 4, "identity",
3792 					   TEXTOID, -1, 0);
3793 
3794 	tupdesc = BlessTupleDesc(tupdesc);
3795 
3796 	if (is_objectclass_supported(address.classId))
3797 	{
3798 		HeapTuple	objtup;
3799 		Relation	catalog = heap_open(address.classId, AccessShareLock);
3800 
3801 		objtup = get_catalog_object_by_oid(catalog, address.objectId);
3802 		if (objtup != NULL)
3803 		{
3804 			bool		isnull;
3805 			AttrNumber	nspAttnum;
3806 			AttrNumber	nameAttnum;
3807 
3808 			nspAttnum = get_object_attnum_namespace(address.classId);
3809 			if (nspAttnum != InvalidAttrNumber)
3810 			{
3811 				schema_oid = heap_getattr(objtup, nspAttnum,
3812 										  RelationGetDescr(catalog), &isnull);
3813 				if (isnull)
3814 					elog(ERROR, "invalid null namespace in object %u/%u/%d",
3815 						 address.classId, address.objectId, address.objectSubId);
3816 			}
3817 
3818 			/*
3819 			 * We only return the object name if it can be used (together with
3820 			 * the schema name, if any) as a unique identifier.
3821 			 */
3822 			if (get_object_namensp_unique(address.classId))
3823 			{
3824 				nameAttnum = get_object_attnum_name(address.classId);
3825 				if (nameAttnum != InvalidAttrNumber)
3826 				{
3827 					Datum		nameDatum;
3828 
3829 					nameDatum = heap_getattr(objtup, nameAttnum,
3830 											 RelationGetDescr(catalog), &isnull);
3831 					if (isnull)
3832 						elog(ERROR, "invalid null name in object %u/%u/%d",
3833 							 address.classId, address.objectId, address.objectSubId);
3834 					objname = quote_identifier(NameStr(*(DatumGetName(nameDatum))));
3835 				}
3836 			}
3837 		}
3838 
3839 		heap_close(catalog, AccessShareLock);
3840 	}
3841 
3842 	/* object type */
3843 	values[0] = CStringGetTextDatum(getObjectTypeDescription(&address));
3844 	nulls[0] = false;
3845 
3846 	/* schema name */
3847 	if (OidIsValid(schema_oid))
3848 	{
3849 		const char *schema = quote_identifier(get_namespace_name(schema_oid));
3850 
3851 		values[1] = CStringGetTextDatum(schema);
3852 		nulls[1] = false;
3853 	}
3854 	else
3855 		nulls[1] = true;
3856 
3857 	/* object name */
3858 	if (objname)
3859 	{
3860 		values[2] = CStringGetTextDatum(objname);
3861 		nulls[2] = false;
3862 	}
3863 	else
3864 		nulls[2] = true;
3865 
3866 	/* object identity */
3867 	values[3] = CStringGetTextDatum(getObjectIdentity(&address));
3868 	nulls[3] = false;
3869 
3870 	htup = heap_form_tuple(tupdesc, values, nulls);
3871 
3872 	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
3873 }
3874 
3875 /*
3876  * SQL-level callable function to obtain object type + identity
3877  */
3878 Datum
3879 pg_identify_object_as_address(PG_FUNCTION_ARGS)
3880 {
3881 	Oid			classid = PG_GETARG_OID(0);
3882 	Oid			objid = PG_GETARG_OID(1);
3883 	int32		objsubid = PG_GETARG_INT32(2);
3884 	ObjectAddress address;
3885 	char	   *identity;
3886 	List	   *names;
3887 	List	   *args;
3888 	Datum		values[3];
3889 	bool		nulls[3];
3890 	TupleDesc	tupdesc;
3891 	HeapTuple	htup;
3892 
3893 	address.classId = classid;
3894 	address.objectId = objid;
3895 	address.objectSubId = objsubid;
3896 
3897 	/*
3898 	 * Construct a tuple descriptor for the result row.  This must match this
3899 	 * function's pg_proc entry!
3900 	 */
3901 	tupdesc = CreateTemplateTupleDesc(3, false);
3902 	TupleDescInitEntry(tupdesc, (AttrNumber) 1, "type",
3903 					   TEXTOID, -1, 0);
3904 	TupleDescInitEntry(tupdesc, (AttrNumber) 2, "object_names",
3905 					   TEXTARRAYOID, -1, 0);
3906 	TupleDescInitEntry(tupdesc, (AttrNumber) 3, "object_args",
3907 					   TEXTARRAYOID, -1, 0);
3908 
3909 	tupdesc = BlessTupleDesc(tupdesc);
3910 
3911 	/* object type */
3912 	values[0] = CStringGetTextDatum(getObjectTypeDescription(&address));
3913 	nulls[0] = false;
3914 
3915 	/* object identity */
3916 	identity = getObjectIdentityParts(&address, &names, &args);
3917 	pfree(identity);
3918 
3919 	/* object_names */
3920 	if (names != NIL)
3921 		values[1] = PointerGetDatum(strlist_to_textarray(names));
3922 	else
3923 		values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
3924 	nulls[1] = false;
3925 
3926 	/* object_args */
3927 	if (args)
3928 		values[2] = PointerGetDatum(strlist_to_textarray(args));
3929 	else
3930 		values[2] = PointerGetDatum(construct_empty_array(TEXTOID));
3931 	nulls[2] = false;
3932 
3933 	htup = heap_form_tuple(tupdesc, values, nulls);
3934 
3935 	PG_RETURN_DATUM(HeapTupleGetDatum(htup));
3936 }
3937 
3938 /*
3939  * Return a palloc'ed string that describes the type of object that the
3940  * passed address is for.
3941  *
3942  * Keep ObjectTypeMap in sync with this.
3943  */
3944 char *
3945 getObjectTypeDescription(const ObjectAddress *object)
3946 {
3947 	StringInfoData buffer;
3948 
3949 	initStringInfo(&buffer);
3950 
3951 	switch (getObjectClass(object))
3952 	{
3953 		case OCLASS_CLASS:
3954 			getRelationTypeDescription(&buffer, object->objectId,
3955 									   object->objectSubId);
3956 			break;
3957 
3958 		case OCLASS_PROC:
3959 			getProcedureTypeDescription(&buffer, object->objectId);
3960 			break;
3961 
3962 		case OCLASS_TYPE:
3963 			appendStringInfoString(&buffer, "type");
3964 			break;
3965 
3966 		case OCLASS_CAST:
3967 			appendStringInfoString(&buffer, "cast");
3968 			break;
3969 
3970 		case OCLASS_COLLATION:
3971 			appendStringInfoString(&buffer, "collation");
3972 			break;
3973 
3974 		case OCLASS_CONSTRAINT:
3975 			getConstraintTypeDescription(&buffer, object->objectId);
3976 			break;
3977 
3978 		case OCLASS_CONVERSION:
3979 			appendStringInfoString(&buffer, "conversion");
3980 			break;
3981 
3982 		case OCLASS_DEFAULT:
3983 			appendStringInfoString(&buffer, "default value");
3984 			break;
3985 
3986 		case OCLASS_LANGUAGE:
3987 			appendStringInfoString(&buffer, "language");
3988 			break;
3989 
3990 		case OCLASS_LARGEOBJECT:
3991 			appendStringInfoString(&buffer, "large object");
3992 			break;
3993 
3994 		case OCLASS_OPERATOR:
3995 			appendStringInfoString(&buffer, "operator");
3996 			break;
3997 
3998 		case OCLASS_OPCLASS:
3999 			appendStringInfoString(&buffer, "operator class");
4000 			break;
4001 
4002 		case OCLASS_OPFAMILY:
4003 			appendStringInfoString(&buffer, "operator family");
4004 			break;
4005 
4006 		case OCLASS_AM:
4007 			appendStringInfoString(&buffer, "access method");
4008 			break;
4009 
4010 		case OCLASS_AMOP:
4011 			appendStringInfoString(&buffer, "operator of access method");
4012 			break;
4013 
4014 		case OCLASS_AMPROC:
4015 			appendStringInfoString(&buffer, "function of access method");
4016 			break;
4017 
4018 		case OCLASS_REWRITE:
4019 			appendStringInfoString(&buffer, "rule");
4020 			break;
4021 
4022 		case OCLASS_TRIGGER:
4023 			appendStringInfoString(&buffer, "trigger");
4024 			break;
4025 
4026 		case OCLASS_SCHEMA:
4027 			appendStringInfoString(&buffer, "schema");
4028 			break;
4029 
4030 		case OCLASS_STATISTIC_EXT:
4031 			appendStringInfoString(&buffer, "statistics object");
4032 			break;
4033 
4034 		case OCLASS_TSPARSER:
4035 			appendStringInfoString(&buffer, "text search parser");
4036 			break;
4037 
4038 		case OCLASS_TSDICT:
4039 			appendStringInfoString(&buffer, "text search dictionary");
4040 			break;
4041 
4042 		case OCLASS_TSTEMPLATE:
4043 			appendStringInfoString(&buffer, "text search template");
4044 			break;
4045 
4046 		case OCLASS_TSCONFIG:
4047 			appendStringInfoString(&buffer, "text search configuration");
4048 			break;
4049 
4050 		case OCLASS_ROLE:
4051 			appendStringInfoString(&buffer, "role");
4052 			break;
4053 
4054 		case OCLASS_DATABASE:
4055 			appendStringInfoString(&buffer, "database");
4056 			break;
4057 
4058 		case OCLASS_TBLSPACE:
4059 			appendStringInfoString(&buffer, "tablespace");
4060 			break;
4061 
4062 		case OCLASS_FDW:
4063 			appendStringInfoString(&buffer, "foreign-data wrapper");
4064 			break;
4065 
4066 		case OCLASS_FOREIGN_SERVER:
4067 			appendStringInfoString(&buffer, "server");
4068 			break;
4069 
4070 		case OCLASS_USER_MAPPING:
4071 			appendStringInfoString(&buffer, "user mapping");
4072 			break;
4073 
4074 		case OCLASS_DEFACL:
4075 			appendStringInfoString(&buffer, "default acl");
4076 			break;
4077 
4078 		case OCLASS_EXTENSION:
4079 			appendStringInfoString(&buffer, "extension");
4080 			break;
4081 
4082 		case OCLASS_EVENT_TRIGGER:
4083 			appendStringInfoString(&buffer, "event trigger");
4084 			break;
4085 
4086 		case OCLASS_POLICY:
4087 			appendStringInfoString(&buffer, "policy");
4088 			break;
4089 
4090 		case OCLASS_PUBLICATION:
4091 			appendStringInfoString(&buffer, "publication");
4092 			break;
4093 
4094 		case OCLASS_PUBLICATION_REL:
4095 			appendStringInfoString(&buffer, "publication relation");
4096 			break;
4097 
4098 		case OCLASS_SUBSCRIPTION:
4099 			appendStringInfoString(&buffer, "subscription");
4100 			break;
4101 
4102 		case OCLASS_TRANSFORM:
4103 			appendStringInfoString(&buffer, "transform");
4104 			break;
4105 
4106 			/*
4107 			 * There's intentionally no default: case here; we want the
4108 			 * compiler to warn if a new OCLASS hasn't been handled above.
4109 			 */
4110 	}
4111 
4112 	return buffer.data;
4113 }
4114 
4115 /*
4116  * subroutine for getObjectTypeDescription: describe a relation type
4117  */
4118 static void
4119 getRelationTypeDescription(StringInfo buffer, Oid relid, int32 objectSubId)
4120 {
4121 	HeapTuple	relTup;
4122 	Form_pg_class relForm;
4123 
4124 	relTup = SearchSysCache1(RELOID,
4125 							 ObjectIdGetDatum(relid));
4126 	if (!HeapTupleIsValid(relTup))
4127 		elog(ERROR, "cache lookup failed for relation %u", relid);
4128 	relForm = (Form_pg_class) GETSTRUCT(relTup);
4129 
4130 	switch (relForm->relkind)
4131 	{
4132 		case RELKIND_RELATION:
4133 		case RELKIND_PARTITIONED_TABLE:
4134 			appendStringInfoString(buffer, "table");
4135 			break;
4136 		case RELKIND_INDEX:
4137 		case RELKIND_PARTITIONED_INDEX:
4138 			appendStringInfoString(buffer, "index");
4139 			break;
4140 		case RELKIND_SEQUENCE:
4141 			appendStringInfoString(buffer, "sequence");
4142 			break;
4143 		case RELKIND_TOASTVALUE:
4144 			appendStringInfoString(buffer, "toast table");
4145 			break;
4146 		case RELKIND_VIEW:
4147 			appendStringInfoString(buffer, "view");
4148 			break;
4149 		case RELKIND_MATVIEW:
4150 			appendStringInfoString(buffer, "materialized view");
4151 			break;
4152 		case RELKIND_COMPOSITE_TYPE:
4153 			appendStringInfoString(buffer, "composite type");
4154 			break;
4155 		case RELKIND_FOREIGN_TABLE:
4156 			appendStringInfoString(buffer, "foreign table");
4157 			break;
4158 		default:
4159 			/* shouldn't get here */
4160 			appendStringInfoString(buffer, "relation");
4161 			break;
4162 	}
4163 
4164 	if (objectSubId != 0)
4165 		appendStringInfoString(buffer, " column");
4166 
4167 	ReleaseSysCache(relTup);
4168 }
4169 
4170 /*
4171  * subroutine for getObjectTypeDescription: describe a constraint type
4172  */
4173 static void
4174 getConstraintTypeDescription(StringInfo buffer, Oid constroid)
4175 {
4176 	Relation	constrRel;
4177 	HeapTuple	constrTup;
4178 	Form_pg_constraint constrForm;
4179 
4180 	constrRel = heap_open(ConstraintRelationId, AccessShareLock);
4181 	constrTup = get_catalog_object_by_oid(constrRel, constroid);
4182 	if (!HeapTupleIsValid(constrTup))
4183 		elog(ERROR, "cache lookup failed for constraint %u", constroid);
4184 
4185 	constrForm = (Form_pg_constraint) GETSTRUCT(constrTup);
4186 
4187 	if (OidIsValid(constrForm->conrelid))
4188 		appendStringInfoString(buffer, "table constraint");
4189 	else if (OidIsValid(constrForm->contypid))
4190 		appendStringInfoString(buffer, "domain constraint");
4191 	else
4192 		elog(ERROR, "invalid constraint %u", HeapTupleGetOid(constrTup));
4193 
4194 	heap_close(constrRel, AccessShareLock);
4195 }
4196 
4197 /*
4198  * subroutine for getObjectTypeDescription: describe a procedure type
4199  */
4200 static void
4201 getProcedureTypeDescription(StringInfo buffer, Oid procid)
4202 {
4203 	HeapTuple	procTup;
4204 	Form_pg_proc procForm;
4205 
4206 	procTup = SearchSysCache1(PROCOID,
4207 							  ObjectIdGetDatum(procid));
4208 	if (!HeapTupleIsValid(procTup))
4209 		elog(ERROR, "cache lookup failed for procedure %u", procid);
4210 	procForm = (Form_pg_proc) GETSTRUCT(procTup);
4211 
4212 	if (procForm->prokind == PROKIND_AGGREGATE)
4213 		appendStringInfoString(buffer, "aggregate");
4214 	else if (procForm->prokind == PROKIND_PROCEDURE)
4215 		appendStringInfoString(buffer, "procedure");
4216 	else						/* function or window function */
4217 		appendStringInfoString(buffer, "function");
4218 
4219 	ReleaseSysCache(procTup);
4220 }
4221 
4222 /*
4223  * Obtain a given object's identity, as a palloc'ed string.
4224  *
4225  * This is for machine consumption, so it's not translated.  All elements are
4226  * schema-qualified when appropriate.
4227  */
4228 char *
4229 getObjectIdentity(const ObjectAddress *object)
4230 {
4231 	return getObjectIdentityParts(object, NULL, NULL);
4232 }
4233 
4234 /*
4235  * As above, but more detailed.
4236  *
4237  * There are two sets of return values: the identity itself as a palloc'd
4238  * string is returned.  objname and objargs, if not NULL, are output parameters
4239  * that receive lists of C-strings that are useful to give back to
4240  * get_object_address() to reconstruct the ObjectAddress.
4241  */
4242 char *
4243 getObjectIdentityParts(const ObjectAddress *object,
4244 					   List **objname, List **objargs)
4245 {
4246 	StringInfoData buffer;
4247 
4248 	initStringInfo(&buffer);
4249 
4250 	/*
4251 	 * Make sure that both objname and objargs were passed, or none was; and
4252 	 * initialize them to empty lists.  For objname this is useless because it
4253 	 * will be initialized in all cases inside the switch; but we do it anyway
4254 	 * so that we can test below that no branch leaves it unset.
4255 	 */
4256 	Assert(PointerIsValid(objname) == PointerIsValid(objargs));
4257 	if (objname)
4258 	{
4259 		*objname = NIL;
4260 		*objargs = NIL;
4261 	}
4262 
4263 	switch (getObjectClass(object))
4264 	{
4265 		case OCLASS_CLASS:
4266 			getRelationIdentity(&buffer, object->objectId, objname);
4267 			if (object->objectSubId != 0)
4268 			{
4269 				char	   *attr;
4270 
4271 				attr = get_attname(object->objectId, object->objectSubId,
4272 								   false);
4273 				appendStringInfo(&buffer, ".%s", quote_identifier(attr));
4274 				if (objname)
4275 					*objname = lappend(*objname, attr);
4276 			}
4277 			break;
4278 
4279 		case OCLASS_PROC:
4280 			appendStringInfoString(&buffer,
4281 								   format_procedure_qualified(object->objectId));
4282 			if (objname)
4283 				format_procedure_parts(object->objectId, objname, objargs);
4284 			break;
4285 
4286 		case OCLASS_TYPE:
4287 			{
4288 				char	   *typeout;
4289 
4290 				typeout = format_type_be_qualified(object->objectId);
4291 				appendStringInfoString(&buffer, typeout);
4292 				if (objname)
4293 					*objname = list_make1(typeout);
4294 			}
4295 			break;
4296 
4297 		case OCLASS_CAST:
4298 			{
4299 				Relation	castRel;
4300 				HeapTuple	tup;
4301 				Form_pg_cast castForm;
4302 
4303 				castRel = heap_open(CastRelationId, AccessShareLock);
4304 
4305 				tup = get_catalog_object_by_oid(castRel, object->objectId);
4306 
4307 				if (!HeapTupleIsValid(tup))
4308 					elog(ERROR, "could not find tuple for cast %u",
4309 						 object->objectId);
4310 
4311 				castForm = (Form_pg_cast) GETSTRUCT(tup);
4312 
4313 				appendStringInfo(&buffer, "(%s AS %s)",
4314 								 format_type_be_qualified(castForm->castsource),
4315 								 format_type_be_qualified(castForm->casttarget));
4316 
4317 				if (objname)
4318 				{
4319 					*objname = list_make1(format_type_be_qualified(castForm->castsource));
4320 					*objargs = list_make1(format_type_be_qualified(castForm->casttarget));
4321 				}
4322 
4323 				heap_close(castRel, AccessShareLock);
4324 				break;
4325 			}
4326 
4327 		case OCLASS_COLLATION:
4328 			{
4329 				HeapTuple	collTup;
4330 				Form_pg_collation coll;
4331 				char	   *schema;
4332 
4333 				collTup = SearchSysCache1(COLLOID,
4334 										  ObjectIdGetDatum(object->objectId));
4335 				if (!HeapTupleIsValid(collTup))
4336 					elog(ERROR, "cache lookup failed for collation %u",
4337 						 object->objectId);
4338 				coll = (Form_pg_collation) GETSTRUCT(collTup);
4339 				schema = get_namespace_name_or_temp(coll->collnamespace);
4340 				appendStringInfoString(&buffer,
4341 									   quote_qualified_identifier(schema,
4342 																  NameStr(coll->collname)));
4343 				if (objname)
4344 					*objname = list_make2(schema,
4345 										  pstrdup(NameStr(coll->collname)));
4346 				ReleaseSysCache(collTup);
4347 				break;
4348 			}
4349 
4350 		case OCLASS_CONSTRAINT:
4351 			{
4352 				HeapTuple	conTup;
4353 				Form_pg_constraint con;
4354 
4355 				conTup = SearchSysCache1(CONSTROID,
4356 										 ObjectIdGetDatum(object->objectId));
4357 				if (!HeapTupleIsValid(conTup))
4358 					elog(ERROR, "cache lookup failed for constraint %u",
4359 						 object->objectId);
4360 				con = (Form_pg_constraint) GETSTRUCT(conTup);
4361 
4362 				if (OidIsValid(con->conrelid))
4363 				{
4364 					appendStringInfo(&buffer, "%s on ",
4365 									 quote_identifier(NameStr(con->conname)));
4366 					getRelationIdentity(&buffer, con->conrelid, objname);
4367 					if (objname)
4368 						*objname = lappend(*objname, pstrdup(NameStr(con->conname)));
4369 				}
4370 				else
4371 				{
4372 					ObjectAddress domain;
4373 
4374 					Assert(OidIsValid(con->contypid));
4375 					domain.classId = TypeRelationId;
4376 					domain.objectId = con->contypid;
4377 					domain.objectSubId = 0;
4378 
4379 					appendStringInfo(&buffer, "%s on %s",
4380 									 quote_identifier(NameStr(con->conname)),
4381 									 getObjectIdentityParts(&domain, objname, objargs));
4382 
4383 					if (objname)
4384 						*objargs = lappend(*objargs, pstrdup(NameStr(con->conname)));
4385 				}
4386 
4387 				ReleaseSysCache(conTup);
4388 				break;
4389 			}
4390 
4391 		case OCLASS_CONVERSION:
4392 			{
4393 				HeapTuple	conTup;
4394 				Form_pg_conversion conForm;
4395 				char	   *schema;
4396 
4397 				conTup = SearchSysCache1(CONVOID,
4398 										 ObjectIdGetDatum(object->objectId));
4399 				if (!HeapTupleIsValid(conTup))
4400 					elog(ERROR, "cache lookup failed for conversion %u",
4401 						 object->objectId);
4402 				conForm = (Form_pg_conversion) GETSTRUCT(conTup);
4403 				schema = get_namespace_name_or_temp(conForm->connamespace);
4404 				appendStringInfoString(&buffer,
4405 									   quote_qualified_identifier(schema,
4406 																  NameStr(conForm->conname)));
4407 				if (objname)
4408 					*objname = list_make2(schema,
4409 										  pstrdup(NameStr(conForm->conname)));
4410 				ReleaseSysCache(conTup);
4411 				break;
4412 			}
4413 
4414 		case OCLASS_DEFAULT:
4415 			{
4416 				Relation	attrdefDesc;
4417 				ScanKeyData skey[1];
4418 				SysScanDesc adscan;
4419 
4420 				HeapTuple	tup;
4421 				Form_pg_attrdef attrdef;
4422 				ObjectAddress colobject;
4423 
4424 				attrdefDesc = heap_open(AttrDefaultRelationId, AccessShareLock);
4425 
4426 				ScanKeyInit(&skey[0],
4427 							ObjectIdAttributeNumber,
4428 							BTEqualStrategyNumber, F_OIDEQ,
4429 							ObjectIdGetDatum(object->objectId));
4430 
4431 				adscan = systable_beginscan(attrdefDesc, AttrDefaultOidIndexId,
4432 											true, NULL, 1, skey);
4433 
4434 				tup = systable_getnext(adscan);
4435 
4436 				if (!HeapTupleIsValid(tup))
4437 					elog(ERROR, "could not find tuple for attrdef %u",
4438 						 object->objectId);
4439 
4440 				attrdef = (Form_pg_attrdef) GETSTRUCT(tup);
4441 
4442 				colobject.classId = RelationRelationId;
4443 				colobject.objectId = attrdef->adrelid;
4444 				colobject.objectSubId = attrdef->adnum;
4445 
4446 				appendStringInfo(&buffer, "for %s",
4447 								 getObjectIdentityParts(&colobject,
4448 														objname, objargs));
4449 
4450 				systable_endscan(adscan);
4451 				heap_close(attrdefDesc, AccessShareLock);
4452 				break;
4453 			}
4454 
4455 		case OCLASS_LANGUAGE:
4456 			{
4457 				HeapTuple	langTup;
4458 				Form_pg_language langForm;
4459 
4460 				langTup = SearchSysCache1(LANGOID,
4461 										  ObjectIdGetDatum(object->objectId));
4462 				if (!HeapTupleIsValid(langTup))
4463 					elog(ERROR, "cache lookup failed for language %u",
4464 						 object->objectId);
4465 				langForm = (Form_pg_language) GETSTRUCT(langTup);
4466 				appendStringInfoString(&buffer,
4467 									   quote_identifier(NameStr(langForm->lanname)));
4468 				if (objname)
4469 					*objname = list_make1(pstrdup(NameStr(langForm->lanname)));
4470 				ReleaseSysCache(langTup);
4471 				break;
4472 			}
4473 		case OCLASS_LARGEOBJECT:
4474 			appendStringInfo(&buffer, "%u",
4475 							 object->objectId);
4476 			if (objname)
4477 				*objname = list_make1(psprintf("%u", object->objectId));
4478 			break;
4479 
4480 		case OCLASS_OPERATOR:
4481 			appendStringInfoString(&buffer,
4482 								   format_operator_qualified(object->objectId));
4483 			if (objname)
4484 				format_operator_parts(object->objectId, objname, objargs);
4485 			break;
4486 
4487 		case OCLASS_OPCLASS:
4488 			{
4489 				HeapTuple	opcTup;
4490 				Form_pg_opclass opcForm;
4491 				HeapTuple	amTup;
4492 				Form_pg_am	amForm;
4493 				char	   *schema;
4494 
4495 				opcTup = SearchSysCache1(CLAOID,
4496 										 ObjectIdGetDatum(object->objectId));
4497 				if (!HeapTupleIsValid(opcTup))
4498 					elog(ERROR, "cache lookup failed for opclass %u",
4499 						 object->objectId);
4500 				opcForm = (Form_pg_opclass) GETSTRUCT(opcTup);
4501 				schema = get_namespace_name_or_temp(opcForm->opcnamespace);
4502 
4503 				amTup = SearchSysCache1(AMOID,
4504 										ObjectIdGetDatum(opcForm->opcmethod));
4505 				if (!HeapTupleIsValid(amTup))
4506 					elog(ERROR, "cache lookup failed for access method %u",
4507 						 opcForm->opcmethod);
4508 				amForm = (Form_pg_am) GETSTRUCT(amTup);
4509 
4510 				appendStringInfo(&buffer, "%s USING %s",
4511 								 quote_qualified_identifier(schema,
4512 															NameStr(opcForm->opcname)),
4513 								 quote_identifier(NameStr(amForm->amname)));
4514 				if (objname)
4515 					*objname = list_make3(pstrdup(NameStr(amForm->amname)),
4516 										  schema,
4517 										  pstrdup(NameStr(opcForm->opcname)));
4518 
4519 				ReleaseSysCache(amTup);
4520 				ReleaseSysCache(opcTup);
4521 				break;
4522 			}
4523 
4524 		case OCLASS_OPFAMILY:
4525 			getOpFamilyIdentity(&buffer, object->objectId, objname);
4526 			break;
4527 
4528 		case OCLASS_AM:
4529 			{
4530 				char	   *amname;
4531 
4532 				amname = get_am_name(object->objectId);
4533 				if (!amname)
4534 					elog(ERROR, "cache lookup failed for access method %u",
4535 						 object->objectId);
4536 				appendStringInfoString(&buffer, quote_identifier(amname));
4537 				if (objname)
4538 					*objname = list_make1(amname);
4539 			}
4540 			break;
4541 
4542 		case OCLASS_AMOP:
4543 			{
4544 				Relation	amopDesc;
4545 				HeapTuple	tup;
4546 				ScanKeyData skey[1];
4547 				SysScanDesc amscan;
4548 				Form_pg_amop amopForm;
4549 				StringInfoData opfam;
4550 				char	   *ltype;
4551 				char	   *rtype;
4552 
4553 				amopDesc = heap_open(AccessMethodOperatorRelationId,
4554 									 AccessShareLock);
4555 
4556 				ScanKeyInit(&skey[0],
4557 							ObjectIdAttributeNumber,
4558 							BTEqualStrategyNumber, F_OIDEQ,
4559 							ObjectIdGetDatum(object->objectId));
4560 
4561 				amscan = systable_beginscan(amopDesc, AccessMethodOperatorOidIndexId, true,
4562 											NULL, 1, skey);
4563 
4564 				tup = systable_getnext(amscan);
4565 
4566 				if (!HeapTupleIsValid(tup))
4567 					elog(ERROR, "could not find tuple for amop entry %u",
4568 						 object->objectId);
4569 
4570 				amopForm = (Form_pg_amop) GETSTRUCT(tup);
4571 
4572 				initStringInfo(&opfam);
4573 				getOpFamilyIdentity(&opfam, amopForm->amopfamily, objname);
4574 
4575 				ltype = format_type_be_qualified(amopForm->amoplefttype);
4576 				rtype = format_type_be_qualified(amopForm->amoprighttype);
4577 
4578 				if (objname)
4579 				{
4580 					*objname = lappend(*objname,
4581 									   psprintf("%d", amopForm->amopstrategy));
4582 					*objargs = list_make2(ltype, rtype);
4583 				}
4584 
4585 				appendStringInfo(&buffer, "operator %d (%s, %s) of %s",
4586 								 amopForm->amopstrategy,
4587 								 ltype, rtype, opfam.data);
4588 
4589 				pfree(opfam.data);
4590 
4591 				systable_endscan(amscan);
4592 				heap_close(amopDesc, AccessShareLock);
4593 				break;
4594 			}
4595 
4596 		case OCLASS_AMPROC:
4597 			{
4598 				Relation	amprocDesc;
4599 				ScanKeyData skey[1];
4600 				SysScanDesc amscan;
4601 				HeapTuple	tup;
4602 				Form_pg_amproc amprocForm;
4603 				StringInfoData opfam;
4604 				char	   *ltype;
4605 				char	   *rtype;
4606 
4607 				amprocDesc = heap_open(AccessMethodProcedureRelationId,
4608 									   AccessShareLock);
4609 
4610 				ScanKeyInit(&skey[0],
4611 							ObjectIdAttributeNumber,
4612 							BTEqualStrategyNumber, F_OIDEQ,
4613 							ObjectIdGetDatum(object->objectId));
4614 
4615 				amscan = systable_beginscan(amprocDesc, AccessMethodProcedureOidIndexId, true,
4616 											NULL, 1, skey);
4617 
4618 				tup = systable_getnext(amscan);
4619 
4620 				if (!HeapTupleIsValid(tup))
4621 					elog(ERROR, "could not find tuple for amproc entry %u",
4622 						 object->objectId);
4623 
4624 				amprocForm = (Form_pg_amproc) GETSTRUCT(tup);
4625 
4626 				initStringInfo(&opfam);
4627 				getOpFamilyIdentity(&opfam, amprocForm->amprocfamily, objname);
4628 
4629 				ltype = format_type_be_qualified(amprocForm->amproclefttype);
4630 				rtype = format_type_be_qualified(amprocForm->amprocrighttype);
4631 
4632 				if (objname)
4633 				{
4634 					*objname = lappend(*objname,
4635 									   psprintf("%d", amprocForm->amprocnum));
4636 					*objargs = list_make2(ltype, rtype);
4637 				}
4638 
4639 				appendStringInfo(&buffer, "function %d (%s, %s) of %s",
4640 								 amprocForm->amprocnum,
4641 								 ltype, rtype, opfam.data);
4642 
4643 				pfree(opfam.data);
4644 
4645 				systable_endscan(amscan);
4646 				heap_close(amprocDesc, AccessShareLock);
4647 				break;
4648 			}
4649 
4650 		case OCLASS_REWRITE:
4651 			{
4652 				Relation	ruleDesc;
4653 				HeapTuple	tup;
4654 				Form_pg_rewrite rule;
4655 
4656 				ruleDesc = heap_open(RewriteRelationId, AccessShareLock);
4657 
4658 				tup = get_catalog_object_by_oid(ruleDesc, object->objectId);
4659 
4660 				if (!HeapTupleIsValid(tup))
4661 					elog(ERROR, "could not find tuple for rule %u",
4662 						 object->objectId);
4663 
4664 				rule = (Form_pg_rewrite) GETSTRUCT(tup);
4665 
4666 				appendStringInfo(&buffer, "%s on ",
4667 								 quote_identifier(NameStr(rule->rulename)));
4668 				getRelationIdentity(&buffer, rule->ev_class, objname);
4669 				if (objname)
4670 					*objname = lappend(*objname, pstrdup(NameStr(rule->rulename)));
4671 
4672 				heap_close(ruleDesc, AccessShareLock);
4673 				break;
4674 			}
4675 
4676 		case OCLASS_TRIGGER:
4677 			{
4678 				Relation	trigDesc;
4679 				HeapTuple	tup;
4680 				Form_pg_trigger trig;
4681 
4682 				trigDesc = heap_open(TriggerRelationId, AccessShareLock);
4683 
4684 				tup = get_catalog_object_by_oid(trigDesc, object->objectId);
4685 
4686 				if (!HeapTupleIsValid(tup))
4687 					elog(ERROR, "could not find tuple for trigger %u",
4688 						 object->objectId);
4689 
4690 				trig = (Form_pg_trigger) GETSTRUCT(tup);
4691 
4692 				appendStringInfo(&buffer, "%s on ",
4693 								 quote_identifier(NameStr(trig->tgname)));
4694 				getRelationIdentity(&buffer, trig->tgrelid, objname);
4695 				if (objname)
4696 					*objname = lappend(*objname, pstrdup(NameStr(trig->tgname)));
4697 
4698 				heap_close(trigDesc, AccessShareLock);
4699 				break;
4700 			}
4701 
4702 		case OCLASS_SCHEMA:
4703 			{
4704 				char	   *nspname;
4705 
4706 				nspname = get_namespace_name_or_temp(object->objectId);
4707 				if (!nspname)
4708 					elog(ERROR, "cache lookup failed for namespace %u",
4709 						 object->objectId);
4710 				appendStringInfoString(&buffer,
4711 									   quote_identifier(nspname));
4712 				if (objname)
4713 					*objname = list_make1(nspname);
4714 				break;
4715 			}
4716 
4717 		case OCLASS_STATISTIC_EXT:
4718 			{
4719 				HeapTuple	tup;
4720 				Form_pg_statistic_ext formStatistic;
4721 				char	   *schema;
4722 
4723 				tup = SearchSysCache1(STATEXTOID,
4724 									  ObjectIdGetDatum(object->objectId));
4725 				if (!HeapTupleIsValid(tup))
4726 					elog(ERROR, "cache lookup failed for statistics object %u",
4727 						 object->objectId);
4728 				formStatistic = (Form_pg_statistic_ext) GETSTRUCT(tup);
4729 				schema = get_namespace_name_or_temp(formStatistic->stxnamespace);
4730 				appendStringInfoString(&buffer,
4731 									   quote_qualified_identifier(schema,
4732 																  NameStr(formStatistic->stxname)));
4733 				if (objname)
4734 					*objname = list_make2(schema,
4735 										  pstrdup(NameStr(formStatistic->stxname)));
4736 				ReleaseSysCache(tup);
4737 			}
4738 			break;
4739 
4740 		case OCLASS_TSPARSER:
4741 			{
4742 				HeapTuple	tup;
4743 				Form_pg_ts_parser formParser;
4744 				char	   *schema;
4745 
4746 				tup = SearchSysCache1(TSPARSEROID,
4747 									  ObjectIdGetDatum(object->objectId));
4748 				if (!HeapTupleIsValid(tup))
4749 					elog(ERROR, "cache lookup failed for text search parser %u",
4750 						 object->objectId);
4751 				formParser = (Form_pg_ts_parser) GETSTRUCT(tup);
4752 				schema = get_namespace_name_or_temp(formParser->prsnamespace);
4753 				appendStringInfoString(&buffer,
4754 									   quote_qualified_identifier(schema,
4755 																  NameStr(formParser->prsname)));
4756 				if (objname)
4757 					*objname = list_make2(schema,
4758 										  pstrdup(NameStr(formParser->prsname)));
4759 				ReleaseSysCache(tup);
4760 				break;
4761 			}
4762 
4763 		case OCLASS_TSDICT:
4764 			{
4765 				HeapTuple	tup;
4766 				Form_pg_ts_dict formDict;
4767 				char	   *schema;
4768 
4769 				tup = SearchSysCache1(TSDICTOID,
4770 									  ObjectIdGetDatum(object->objectId));
4771 				if (!HeapTupleIsValid(tup))
4772 					elog(ERROR, "cache lookup failed for text search dictionary %u",
4773 						 object->objectId);
4774 				formDict = (Form_pg_ts_dict) GETSTRUCT(tup);
4775 				schema = get_namespace_name_or_temp(formDict->dictnamespace);
4776 				appendStringInfoString(&buffer,
4777 									   quote_qualified_identifier(schema,
4778 																  NameStr(formDict->dictname)));
4779 				if (objname)
4780 					*objname = list_make2(schema,
4781 										  pstrdup(NameStr(formDict->dictname)));
4782 				ReleaseSysCache(tup);
4783 				break;
4784 			}
4785 
4786 		case OCLASS_TSTEMPLATE:
4787 			{
4788 				HeapTuple	tup;
4789 				Form_pg_ts_template formTmpl;
4790 				char	   *schema;
4791 
4792 				tup = SearchSysCache1(TSTEMPLATEOID,
4793 									  ObjectIdGetDatum(object->objectId));
4794 				if (!HeapTupleIsValid(tup))
4795 					elog(ERROR, "cache lookup failed for text search template %u",
4796 						 object->objectId);
4797 				formTmpl = (Form_pg_ts_template) GETSTRUCT(tup);
4798 				schema = get_namespace_name_or_temp(formTmpl->tmplnamespace);
4799 				appendStringInfoString(&buffer,
4800 									   quote_qualified_identifier(schema,
4801 																  NameStr(formTmpl->tmplname)));
4802 				if (objname)
4803 					*objname = list_make2(schema,
4804 										  pstrdup(NameStr(formTmpl->tmplname)));
4805 				ReleaseSysCache(tup);
4806 				break;
4807 			}
4808 
4809 		case OCLASS_TSCONFIG:
4810 			{
4811 				HeapTuple	tup;
4812 				Form_pg_ts_config formCfg;
4813 				char	   *schema;
4814 
4815 				tup = SearchSysCache1(TSCONFIGOID,
4816 									  ObjectIdGetDatum(object->objectId));
4817 				if (!HeapTupleIsValid(tup))
4818 					elog(ERROR, "cache lookup failed for text search configuration %u",
4819 						 object->objectId);
4820 				formCfg = (Form_pg_ts_config) GETSTRUCT(tup);
4821 				schema = get_namespace_name_or_temp(formCfg->cfgnamespace);
4822 				appendStringInfoString(&buffer,
4823 									   quote_qualified_identifier(schema,
4824 																  NameStr(formCfg->cfgname)));
4825 				if (objname)
4826 					*objname = list_make2(schema,
4827 										  pstrdup(NameStr(formCfg->cfgname)));
4828 				ReleaseSysCache(tup);
4829 				break;
4830 			}
4831 
4832 		case OCLASS_ROLE:
4833 			{
4834 				char	   *username;
4835 
4836 				username = GetUserNameFromId(object->objectId, false);
4837 				if (objname)
4838 					*objname = list_make1(username);
4839 				appendStringInfoString(&buffer,
4840 									   quote_identifier(username));
4841 				break;
4842 			}
4843 
4844 		case OCLASS_DATABASE:
4845 			{
4846 				char	   *datname;
4847 
4848 				datname = get_database_name(object->objectId);
4849 				if (!datname)
4850 					elog(ERROR, "cache lookup failed for database %u",
4851 						 object->objectId);
4852 				if (objname)
4853 					*objname = list_make1(datname);
4854 				appendStringInfoString(&buffer,
4855 									   quote_identifier(datname));
4856 				break;
4857 			}
4858 
4859 		case OCLASS_TBLSPACE:
4860 			{
4861 				char	   *tblspace;
4862 
4863 				tblspace = get_tablespace_name(object->objectId);
4864 				if (!tblspace)
4865 					elog(ERROR, "cache lookup failed for tablespace %u",
4866 						 object->objectId);
4867 				if (objname)
4868 					*objname = list_make1(tblspace);
4869 				appendStringInfoString(&buffer,
4870 									   quote_identifier(tblspace));
4871 				break;
4872 			}
4873 
4874 		case OCLASS_FDW:
4875 			{
4876 				ForeignDataWrapper *fdw;
4877 
4878 				fdw = GetForeignDataWrapper(object->objectId);
4879 				appendStringInfoString(&buffer, quote_identifier(fdw->fdwname));
4880 				if (objname)
4881 					*objname = list_make1(pstrdup(fdw->fdwname));
4882 				break;
4883 			}
4884 
4885 		case OCLASS_FOREIGN_SERVER:
4886 			{
4887 				ForeignServer *srv;
4888 
4889 				srv = GetForeignServer(object->objectId);
4890 				appendStringInfoString(&buffer,
4891 									   quote_identifier(srv->servername));
4892 				if (objname)
4893 					*objname = list_make1(pstrdup(srv->servername));
4894 				break;
4895 			}
4896 
4897 		case OCLASS_USER_MAPPING:
4898 			{
4899 				HeapTuple	tup;
4900 				Oid			useid;
4901 				Form_pg_user_mapping umform;
4902 				ForeignServer *srv;
4903 				const char *usename;
4904 
4905 				tup = SearchSysCache1(USERMAPPINGOID,
4906 									  ObjectIdGetDatum(object->objectId));
4907 				if (!HeapTupleIsValid(tup))
4908 					elog(ERROR, "cache lookup failed for user mapping %u",
4909 						 object->objectId);
4910 				umform = (Form_pg_user_mapping) GETSTRUCT(tup);
4911 				useid = umform->umuser;
4912 				srv = GetForeignServer(umform->umserver);
4913 
4914 				ReleaseSysCache(tup);
4915 
4916 				if (OidIsValid(useid))
4917 					usename = GetUserNameFromId(useid, false);
4918 				else
4919 					usename = "public";
4920 
4921 				if (objname)
4922 				{
4923 					*objname = list_make1(pstrdup(usename));
4924 					*objargs = list_make1(pstrdup(srv->servername));
4925 				}
4926 
4927 				appendStringInfo(&buffer, "%s on server %s",
4928 								 quote_identifier(usename),
4929 								 srv->servername);
4930 				break;
4931 			}
4932 
4933 		case OCLASS_DEFACL:
4934 			{
4935 				Relation	defaclrel;
4936 				ScanKeyData skey[1];
4937 				SysScanDesc rcscan;
4938 				HeapTuple	tup;
4939 				Form_pg_default_acl defacl;
4940 				char	   *schema;
4941 				char	   *username;
4942 
4943 				defaclrel = heap_open(DefaultAclRelationId, AccessShareLock);
4944 
4945 				ScanKeyInit(&skey[0],
4946 							ObjectIdAttributeNumber,
4947 							BTEqualStrategyNumber, F_OIDEQ,
4948 							ObjectIdGetDatum(object->objectId));
4949 
4950 				rcscan = systable_beginscan(defaclrel, DefaultAclOidIndexId,
4951 											true, NULL, 1, skey);
4952 
4953 				tup = systable_getnext(rcscan);
4954 
4955 				if (!HeapTupleIsValid(tup))
4956 					elog(ERROR, "could not find tuple for default ACL %u",
4957 						 object->objectId);
4958 
4959 				defacl = (Form_pg_default_acl) GETSTRUCT(tup);
4960 
4961 				username = GetUserNameFromId(defacl->defaclrole, false);
4962 				appendStringInfo(&buffer,
4963 								 "for role %s",
4964 								 quote_identifier(username));
4965 
4966 				if (OidIsValid(defacl->defaclnamespace))
4967 				{
4968 					schema = get_namespace_name_or_temp(defacl->defaclnamespace);
4969 					appendStringInfo(&buffer,
4970 									 " in schema %s",
4971 									 quote_identifier(schema));
4972 				}
4973 				else
4974 					schema = NULL;
4975 
4976 				switch (defacl->defaclobjtype)
4977 				{
4978 					case DEFACLOBJ_RELATION:
4979 						appendStringInfoString(&buffer,
4980 											   " on tables");
4981 						break;
4982 					case DEFACLOBJ_SEQUENCE:
4983 						appendStringInfoString(&buffer,
4984 											   " on sequences");
4985 						break;
4986 					case DEFACLOBJ_FUNCTION:
4987 						appendStringInfoString(&buffer,
4988 											   " on functions");
4989 						break;
4990 					case DEFACLOBJ_TYPE:
4991 						appendStringInfoString(&buffer,
4992 											   " on types");
4993 						break;
4994 					case DEFACLOBJ_NAMESPACE:
4995 						appendStringInfoString(&buffer,
4996 											   " on schemas");
4997 						break;
4998 				}
4999 
5000 				if (objname)
5001 				{
5002 					*objname = list_make1(username);
5003 					if (schema)
5004 						*objname = lappend(*objname, schema);
5005 					*objargs = list_make1(psprintf("%c", defacl->defaclobjtype));
5006 				}
5007 
5008 				systable_endscan(rcscan);
5009 				heap_close(defaclrel, AccessShareLock);
5010 				break;
5011 			}
5012 
5013 		case OCLASS_EXTENSION:
5014 			{
5015 				char	   *extname;
5016 
5017 				extname = get_extension_name(object->objectId);
5018 				if (!extname)
5019 					elog(ERROR, "cache lookup failed for extension %u",
5020 						 object->objectId);
5021 				appendStringInfoString(&buffer, quote_identifier(extname));
5022 				if (objname)
5023 					*objname = list_make1(extname);
5024 				break;
5025 			}
5026 
5027 		case OCLASS_EVENT_TRIGGER:
5028 			{
5029 				HeapTuple	tup;
5030 				Form_pg_event_trigger trigForm;
5031 				char	   *evtname;
5032 
5033 				tup = SearchSysCache1(EVENTTRIGGEROID,
5034 									  ObjectIdGetDatum(object->objectId));
5035 				if (!HeapTupleIsValid(tup))
5036 					elog(ERROR, "cache lookup failed for event trigger %u",
5037 						 object->objectId);
5038 				trigForm = (Form_pg_event_trigger) GETSTRUCT(tup);
5039 				evtname = pstrdup(NameStr(trigForm->evtname));
5040 				appendStringInfoString(&buffer, quote_identifier(evtname));
5041 				if (objname)
5042 					*objname = list_make1(evtname);
5043 				ReleaseSysCache(tup);
5044 				break;
5045 			}
5046 
5047 		case OCLASS_POLICY:
5048 			{
5049 				Relation	polDesc;
5050 				HeapTuple	tup;
5051 				Form_pg_policy policy;
5052 
5053 				polDesc = heap_open(PolicyRelationId, AccessShareLock);
5054 
5055 				tup = get_catalog_object_by_oid(polDesc, object->objectId);
5056 
5057 				if (!HeapTupleIsValid(tup))
5058 					elog(ERROR, "could not find tuple for policy %u",
5059 						 object->objectId);
5060 
5061 				policy = (Form_pg_policy) GETSTRUCT(tup);
5062 
5063 				appendStringInfo(&buffer, "%s on ",
5064 								 quote_identifier(NameStr(policy->polname)));
5065 				getRelationIdentity(&buffer, policy->polrelid, objname);
5066 				if (objname)
5067 					*objname = lappend(*objname, pstrdup(NameStr(policy->polname)));
5068 
5069 				heap_close(polDesc, AccessShareLock);
5070 				break;
5071 			}
5072 
5073 		case OCLASS_PUBLICATION:
5074 			{
5075 				char	   *pubname;
5076 
5077 				pubname = get_publication_name(object->objectId);
5078 				appendStringInfoString(&buffer,
5079 									   quote_identifier(pubname));
5080 				if (objname)
5081 					*objname = list_make1(pubname);
5082 				break;
5083 			}
5084 
5085 		case OCLASS_PUBLICATION_REL:
5086 			{
5087 				HeapTuple	tup;
5088 				char	   *pubname;
5089 				Form_pg_publication_rel prform;
5090 
5091 				tup = SearchSysCache1(PUBLICATIONREL,
5092 									  ObjectIdGetDatum(object->objectId));
5093 				if (!HeapTupleIsValid(tup))
5094 					elog(ERROR, "cache lookup failed for publication table %u",
5095 						 object->objectId);
5096 
5097 				prform = (Form_pg_publication_rel) GETSTRUCT(tup);
5098 				pubname = get_publication_name(prform->prpubid);
5099 
5100 				getRelationIdentity(&buffer, prform->prrelid, objname);
5101 				appendStringInfo(&buffer, " in publication %s", pubname);
5102 
5103 				if (objargs)
5104 					*objargs = list_make1(pubname);
5105 
5106 				ReleaseSysCache(tup);
5107 				break;
5108 			}
5109 
5110 		case OCLASS_SUBSCRIPTION:
5111 			{
5112 				char	   *subname;
5113 
5114 				subname = get_subscription_name(object->objectId);
5115 				appendStringInfoString(&buffer,
5116 									   quote_identifier(subname));
5117 				if (objname)
5118 					*objname = list_make1(subname);
5119 				break;
5120 			}
5121 
5122 		case OCLASS_TRANSFORM:
5123 			{
5124 				Relation	transformDesc;
5125 				HeapTuple	tup;
5126 				Form_pg_transform transform;
5127 				char	   *transformLang;
5128 				char	   *transformType;
5129 
5130 				transformDesc = heap_open(TransformRelationId, AccessShareLock);
5131 
5132 				tup = get_catalog_object_by_oid(transformDesc, object->objectId);
5133 
5134 				if (!HeapTupleIsValid(tup))
5135 					elog(ERROR, "could not find tuple for transform %u",
5136 						 object->objectId);
5137 
5138 				transform = (Form_pg_transform) GETSTRUCT(tup);
5139 
5140 				transformType = format_type_be_qualified(transform->trftype);
5141 				transformLang = get_language_name(transform->trflang, false);
5142 
5143 				appendStringInfo(&buffer, "for %s on language %s",
5144 								 transformType,
5145 								 transformLang);
5146 				if (objname)
5147 				{
5148 					*objname = list_make1(transformType);
5149 					*objargs = list_make1(pstrdup(transformLang));
5150 				}
5151 
5152 				heap_close(transformDesc, AccessShareLock);
5153 			}
5154 			break;
5155 
5156 			/*
5157 			 * There's intentionally no default: case here; we want the
5158 			 * compiler to warn if a new OCLASS hasn't been handled above.
5159 			 */
5160 	}
5161 
5162 	/*
5163 	 * If a get_object_address representation was requested, make sure we are
5164 	 * providing one.  We don't check objargs, because many of the cases above
5165 	 * leave it as NIL.
5166 	 */
5167 	if (objname && *objname == NIL)
5168 		elog(ERROR, "requested object address for unsupported object class %d: text result \"%s\"",
5169 			 (int) getObjectClass(object), buffer.data);
5170 
5171 	return buffer.data;
5172 }
5173 
5174 static void
5175 getOpFamilyIdentity(StringInfo buffer, Oid opfid, List **object)
5176 {
5177 	HeapTuple	opfTup;
5178 	Form_pg_opfamily opfForm;
5179 	HeapTuple	amTup;
5180 	Form_pg_am	amForm;
5181 	char	   *schema;
5182 
5183 	opfTup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfid));
5184 	if (!HeapTupleIsValid(opfTup))
5185 		elog(ERROR, "cache lookup failed for opfamily %u", opfid);
5186 	opfForm = (Form_pg_opfamily) GETSTRUCT(opfTup);
5187 
5188 	amTup = SearchSysCache1(AMOID, ObjectIdGetDatum(opfForm->opfmethod));
5189 	if (!HeapTupleIsValid(amTup))
5190 		elog(ERROR, "cache lookup failed for access method %u",
5191 			 opfForm->opfmethod);
5192 	amForm = (Form_pg_am) GETSTRUCT(amTup);
5193 
5194 	schema = get_namespace_name_or_temp(opfForm->opfnamespace);
5195 	appendStringInfo(buffer, "%s USING %s",
5196 					 quote_qualified_identifier(schema,
5197 												NameStr(opfForm->opfname)),
5198 					 NameStr(amForm->amname));
5199 
5200 	if (object)
5201 		*object = list_make3(pstrdup(NameStr(amForm->amname)),
5202 							 pstrdup(schema),
5203 							 pstrdup(NameStr(opfForm->opfname)));
5204 
5205 	ReleaseSysCache(amTup);
5206 	ReleaseSysCache(opfTup);
5207 }
5208 
5209 /*
5210  * Append the relation identity (quoted qualified name) to the given
5211  * StringInfo.
5212  */
5213 static void
5214 getRelationIdentity(StringInfo buffer, Oid relid, List **object)
5215 {
5216 	HeapTuple	relTup;
5217 	Form_pg_class relForm;
5218 	char	   *schema;
5219 
5220 	relTup = SearchSysCache1(RELOID,
5221 							 ObjectIdGetDatum(relid));
5222 	if (!HeapTupleIsValid(relTup))
5223 		elog(ERROR, "cache lookup failed for relation %u", relid);
5224 	relForm = (Form_pg_class) GETSTRUCT(relTup);
5225 
5226 	schema = get_namespace_name_or_temp(relForm->relnamespace);
5227 	appendStringInfoString(buffer,
5228 						   quote_qualified_identifier(schema,
5229 													  NameStr(relForm->relname)));
5230 	if (object)
5231 		*object = list_make2(schema, pstrdup(NameStr(relForm->relname)));
5232 
5233 	ReleaseSysCache(relTup);
5234 }
5235 
5236 /*
5237  * Auxiliary function to build a TEXT array out of a list of C-strings.
5238  */
5239 ArrayType *
5240 strlist_to_textarray(List *list)
5241 {
5242 	ArrayType  *arr;
5243 	Datum	   *datums;
5244 	bool	   *nulls;
5245 	int			j = 0;
5246 	ListCell   *cell;
5247 	MemoryContext memcxt;
5248 	MemoryContext oldcxt;
5249 	int			lb[1];
5250 
5251 	/* Work in a temp context; easier than individually pfree'ing the Datums */
5252 	memcxt = AllocSetContextCreate(CurrentMemoryContext,
5253 								   "strlist to array",
5254 								   ALLOCSET_DEFAULT_SIZES);
5255 	oldcxt = MemoryContextSwitchTo(memcxt);
5256 
5257 	datums = (Datum *) palloc(sizeof(Datum) * list_length(list));
5258 	nulls = palloc(sizeof(bool) * list_length(list));
5259 
5260 	foreach(cell, list)
5261 	{
5262 		char	   *name = lfirst(cell);
5263 
5264 		if (name)
5265 		{
5266 			nulls[j] = false;
5267 			datums[j++] = CStringGetTextDatum(name);
5268 		}
5269 		else
5270 			nulls[j] = true;
5271 	}
5272 
5273 	MemoryContextSwitchTo(oldcxt);
5274 
5275 	lb[0] = 1;
5276 	arr = construct_md_array(datums, nulls, 1, &j,
5277 							 lb, TEXTOID, -1, false, 'i');
5278 
5279 	MemoryContextDelete(memcxt);
5280 
5281 	return arr;
5282 }
5283 
5284 /*
5285  * get_relkind_objtype
5286  *
5287  * Return the object type for the relkind given by the caller.
5288  *
5289  * If an unexpected relkind is passed, we say OBJECT_TABLE rather than
5290  * failing.  That's because this is mostly used for generating error messages
5291  * for failed ACL checks on relations, and we'd rather produce a generic
5292  * message saying "table" than fail entirely.
5293  */
5294 ObjectType
5295 get_relkind_objtype(char relkind)
5296 {
5297 	switch (relkind)
5298 	{
5299 		case RELKIND_RELATION:
5300 		case RELKIND_PARTITIONED_TABLE:
5301 			return OBJECT_TABLE;
5302 		case RELKIND_INDEX:
5303 		case RELKIND_PARTITIONED_INDEX:
5304 			return OBJECT_INDEX;
5305 		case RELKIND_SEQUENCE:
5306 			return OBJECT_SEQUENCE;
5307 		case RELKIND_VIEW:
5308 			return OBJECT_VIEW;
5309 		case RELKIND_MATVIEW:
5310 			return OBJECT_MATVIEW;
5311 		case RELKIND_FOREIGN_TABLE:
5312 			return OBJECT_FOREIGN_TABLE;
5313 		case RELKIND_TOASTVALUE:
5314 			return OBJECT_TABLE;
5315 		default:
5316 			/* Per above, don't raise an error */
5317 			return OBJECT_TABLE;
5318 	}
5319 }
5320