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