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