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