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