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