Refactor ownercheck functions
[pgsql.git] / src / backend / catalog / objectaddress.c
blob9dad77c28ac6abbdbb47c9e6c6075454ba22c317
1 /*-------------------------------------------------------------------------
3 * objectaddress.c
4 * functions for working with ObjectAddresses
6 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
10 * IDENTIFICATION
11 * src/backend/catalog/objectaddress.c
13 *-------------------------------------------------------------------------
16 #include "postgres.h"
18 #include "access/genam.h"
19 #include "access/htup_details.h"
20 #include "access/relation.h"
21 #include "access/sysattr.h"
22 #include "access/table.h"
23 #include "catalog/catalog.h"
24 #include "catalog/objectaddress.h"
25 #include "catalog/pg_am.h"
26 #include "catalog/pg_amop.h"
27 #include "catalog/pg_amproc.h"
28 #include "catalog/pg_attrdef.h"
29 #include "catalog/pg_authid.h"
30 #include "catalog/pg_auth_members.h"
31 #include "catalog/pg_cast.h"
32 #include "catalog/pg_collation.h"
33 #include "catalog/pg_constraint.h"
34 #include "catalog/pg_conversion.h"
35 #include "catalog/pg_database.h"
36 #include "catalog/pg_default_acl.h"
37 #include "catalog/pg_enum.h"
38 #include "catalog/pg_event_trigger.h"
39 #include "catalog/pg_extension.h"
40 #include "catalog/pg_foreign_data_wrapper.h"
41 #include "catalog/pg_foreign_server.h"
42 #include "catalog/pg_language.h"
43 #include "catalog/pg_largeobject.h"
44 #include "catalog/pg_largeobject_metadata.h"
45 #include "catalog/pg_namespace.h"
46 #include "catalog/pg_opclass.h"
47 #include "catalog/pg_operator.h"
48 #include "catalog/pg_opfamily.h"
49 #include "catalog/pg_parameter_acl.h"
50 #include "catalog/pg_policy.h"
51 #include "catalog/pg_proc.h"
52 #include "catalog/pg_publication.h"
53 #include "catalog/pg_publication_namespace.h"
54 #include "catalog/pg_publication_rel.h"
55 #include "catalog/pg_rewrite.h"
56 #include "catalog/pg_statistic_ext.h"
57 #include "catalog/pg_subscription.h"
58 #include "catalog/pg_tablespace.h"
59 #include "catalog/pg_transform.h"
60 #include "catalog/pg_trigger.h"
61 #include "catalog/pg_ts_config.h"
62 #include "catalog/pg_ts_dict.h"
63 #include "catalog/pg_ts_parser.h"
64 #include "catalog/pg_ts_template.h"
65 #include "catalog/pg_type.h"
66 #include "catalog/pg_user_mapping.h"
67 #include "commands/dbcommands.h"
68 #include "commands/defrem.h"
69 #include "commands/event_trigger.h"
70 #include "commands/extension.h"
71 #include "commands/policy.h"
72 #include "commands/proclang.h"
73 #include "commands/tablespace.h"
74 #include "commands/trigger.h"
75 #include "foreign/foreign.h"
76 #include "funcapi.h"
77 #include "miscadmin.h"
78 #include "nodes/makefuncs.h"
79 #include "parser/parse_func.h"
80 #include "parser/parse_oper.h"
81 #include "parser/parse_type.h"
82 #include "rewrite/rewriteSupport.h"
83 #include "storage/large_object.h"
84 #include "storage/lmgr.h"
85 #include "storage/sinval.h"
86 #include "utils/acl.h"
87 #include "utils/builtins.h"
88 #include "utils/fmgroids.h"
89 #include "utils/lsyscache.h"
90 #include "utils/memutils.h"
91 #include "utils/regproc.h"
92 #include "utils/syscache.h"
95 * ObjectProperty
97 * This array provides a common part of system object structure; to help
98 * consolidate routines to handle various kind of object classes.
100 typedef struct
102 const char *class_descr; /* string describing the catalog, for internal
103 * error messages */
104 Oid class_oid; /* oid of catalog */
105 Oid oid_index_oid; /* oid of index on system oid column */
106 int oid_catcache_id; /* id of catcache on system oid column */
107 int name_catcache_id; /* id of catcache on (name,namespace), or
108 * (name) if the object does not live in a
109 * namespace */
110 AttrNumber attnum_oid; /* attribute number of oid column */
111 AttrNumber attnum_name; /* attnum of name field */
112 AttrNumber attnum_namespace; /* attnum of namespace field */
113 AttrNumber attnum_owner; /* attnum of owner field */
114 AttrNumber attnum_acl; /* attnum of acl field */
115 ObjectType objtype; /* OBJECT_* of this object type */
116 bool is_nsp_name_unique; /* can the nsp/name combination (or name
117 * alone, if there's no namespace) be
118 * considered a unique identifier for an
119 * object of this class? */
120 } ObjectPropertyType;
122 static const ObjectPropertyType ObjectProperty[] =
125 "access method",
126 AccessMethodRelationId,
127 AmOidIndexId,
128 AMOID,
129 AMNAME,
130 Anum_pg_am_oid,
131 Anum_pg_am_amname,
132 InvalidAttrNumber,
133 InvalidAttrNumber,
134 InvalidAttrNumber,
136 true
139 "access method operator",
140 AccessMethodOperatorRelationId,
141 AccessMethodOperatorOidIndexId,
144 Anum_pg_amop_oid,
145 InvalidAttrNumber,
146 InvalidAttrNumber,
147 InvalidAttrNumber,
148 InvalidAttrNumber,
149 OBJECT_AMOP,
150 false
153 "access method procedure",
154 AccessMethodProcedureRelationId,
155 AccessMethodProcedureOidIndexId,
158 Anum_pg_amproc_oid,
159 InvalidAttrNumber,
160 InvalidAttrNumber,
161 InvalidAttrNumber,
162 InvalidAttrNumber,
163 OBJECT_AMPROC,
164 false
167 "cast",
168 CastRelationId,
169 CastOidIndexId,
172 Anum_pg_cast_oid,
173 InvalidAttrNumber,
174 InvalidAttrNumber,
175 InvalidAttrNumber,
176 InvalidAttrNumber,
178 false
181 "collation",
182 CollationRelationId,
183 CollationOidIndexId,
184 COLLOID,
185 -1, /* COLLNAMEENCNSP also takes encoding */
186 Anum_pg_collation_oid,
187 Anum_pg_collation_collname,
188 Anum_pg_collation_collnamespace,
189 Anum_pg_collation_collowner,
190 InvalidAttrNumber,
191 OBJECT_COLLATION,
192 true
195 "constraint",
196 ConstraintRelationId,
197 ConstraintOidIndexId,
198 CONSTROID,
200 Anum_pg_constraint_oid,
201 Anum_pg_constraint_conname,
202 Anum_pg_constraint_connamespace,
203 InvalidAttrNumber,
204 InvalidAttrNumber,
206 false
209 "conversion",
210 ConversionRelationId,
211 ConversionOidIndexId,
212 CONVOID,
213 CONNAMENSP,
214 Anum_pg_conversion_oid,
215 Anum_pg_conversion_conname,
216 Anum_pg_conversion_connamespace,
217 Anum_pg_conversion_conowner,
218 InvalidAttrNumber,
219 OBJECT_CONVERSION,
220 true
223 "database",
224 DatabaseRelationId,
225 DatabaseOidIndexId,
226 DATABASEOID,
228 Anum_pg_database_oid,
229 Anum_pg_database_datname,
230 InvalidAttrNumber,
231 Anum_pg_database_datdba,
232 Anum_pg_database_datacl,
233 OBJECT_DATABASE,
234 true
237 "default ACL",
238 DefaultAclRelationId,
239 DefaultAclOidIndexId,
242 Anum_pg_default_acl_oid,
243 InvalidAttrNumber,
244 InvalidAttrNumber,
245 InvalidAttrNumber,
246 InvalidAttrNumber,
247 OBJECT_DEFACL,
248 false
251 "extension",
252 ExtensionRelationId,
253 ExtensionOidIndexId,
256 Anum_pg_extension_oid,
257 Anum_pg_extension_extname,
258 InvalidAttrNumber, /* extension doesn't belong to extnamespace */
259 Anum_pg_extension_extowner,
260 InvalidAttrNumber,
261 OBJECT_EXTENSION,
262 true
265 "foreign-data wrapper",
266 ForeignDataWrapperRelationId,
267 ForeignDataWrapperOidIndexId,
268 FOREIGNDATAWRAPPEROID,
269 FOREIGNDATAWRAPPERNAME,
270 Anum_pg_foreign_data_wrapper_oid,
271 Anum_pg_foreign_data_wrapper_fdwname,
272 InvalidAttrNumber,
273 Anum_pg_foreign_data_wrapper_fdwowner,
274 Anum_pg_foreign_data_wrapper_fdwacl,
275 OBJECT_FDW,
276 true
279 "foreign server",
280 ForeignServerRelationId,
281 ForeignServerOidIndexId,
282 FOREIGNSERVEROID,
283 FOREIGNSERVERNAME,
284 Anum_pg_foreign_server_oid,
285 Anum_pg_foreign_server_srvname,
286 InvalidAttrNumber,
287 Anum_pg_foreign_server_srvowner,
288 Anum_pg_foreign_server_srvacl,
289 OBJECT_FOREIGN_SERVER,
290 true
293 "function",
294 ProcedureRelationId,
295 ProcedureOidIndexId,
296 PROCOID,
297 -1, /* PROCNAMEARGSNSP also takes argument types */
298 Anum_pg_proc_oid,
299 Anum_pg_proc_proname,
300 Anum_pg_proc_pronamespace,
301 Anum_pg_proc_proowner,
302 Anum_pg_proc_proacl,
303 OBJECT_FUNCTION,
304 false
307 "language",
308 LanguageRelationId,
309 LanguageOidIndexId,
310 LANGOID,
311 LANGNAME,
312 Anum_pg_language_oid,
313 Anum_pg_language_lanname,
314 InvalidAttrNumber,
315 Anum_pg_language_lanowner,
316 Anum_pg_language_lanacl,
317 OBJECT_LANGUAGE,
318 true
321 "large object metadata",
322 LargeObjectMetadataRelationId,
323 LargeObjectMetadataOidIndexId,
326 Anum_pg_largeobject_metadata_oid,
327 InvalidAttrNumber,
328 InvalidAttrNumber,
329 Anum_pg_largeobject_metadata_lomowner,
330 Anum_pg_largeobject_metadata_lomacl,
331 OBJECT_LARGEOBJECT,
332 false
335 "operator class",
336 OperatorClassRelationId,
337 OpclassOidIndexId,
338 CLAOID,
339 -1, /* CLAAMNAMENSP also takes opcmethod */
340 Anum_pg_opclass_oid,
341 Anum_pg_opclass_opcname,
342 Anum_pg_opclass_opcnamespace,
343 Anum_pg_opclass_opcowner,
344 InvalidAttrNumber,
345 OBJECT_OPCLASS,
346 true
349 "operator",
350 OperatorRelationId,
351 OperatorOidIndexId,
352 OPEROID,
353 -1, /* OPERNAMENSP also takes left and right type */
354 Anum_pg_operator_oid,
355 Anum_pg_operator_oprname,
356 Anum_pg_operator_oprnamespace,
357 Anum_pg_operator_oprowner,
358 InvalidAttrNumber,
359 OBJECT_OPERATOR,
360 false
363 "operator family",
364 OperatorFamilyRelationId,
365 OpfamilyOidIndexId,
366 OPFAMILYOID,
367 -1, /* OPFAMILYAMNAMENSP also takes opfmethod */
368 Anum_pg_opfamily_oid,
369 Anum_pg_opfamily_opfname,
370 Anum_pg_opfamily_opfnamespace,
371 Anum_pg_opfamily_opfowner,
372 InvalidAttrNumber,
373 OBJECT_OPFAMILY,
374 true
377 "role",
378 AuthIdRelationId,
379 AuthIdOidIndexId,
380 AUTHOID,
381 AUTHNAME,
382 Anum_pg_authid_oid,
383 Anum_pg_authid_rolname,
384 InvalidAttrNumber,
385 InvalidAttrNumber,
386 InvalidAttrNumber,
388 true
391 "role membership",
392 AuthMemRelationId,
393 AuthMemOidIndexId,
396 Anum_pg_auth_members_oid,
397 InvalidAttrNumber,
398 InvalidAttrNumber,
399 Anum_pg_auth_members_grantor,
400 InvalidAttrNumber,
402 true
405 "rule",
406 RewriteRelationId,
407 RewriteOidIndexId,
410 Anum_pg_rewrite_oid,
411 Anum_pg_rewrite_rulename,
412 InvalidAttrNumber,
413 InvalidAttrNumber,
414 InvalidAttrNumber,
416 false
419 "schema",
420 NamespaceRelationId,
421 NamespaceOidIndexId,
422 NAMESPACEOID,
423 NAMESPACENAME,
424 Anum_pg_namespace_oid,
425 Anum_pg_namespace_nspname,
426 InvalidAttrNumber,
427 Anum_pg_namespace_nspowner,
428 Anum_pg_namespace_nspacl,
429 OBJECT_SCHEMA,
430 true
433 "relation",
434 RelationRelationId,
435 ClassOidIndexId,
436 RELOID,
437 RELNAMENSP,
438 Anum_pg_class_oid,
439 Anum_pg_class_relname,
440 Anum_pg_class_relnamespace,
441 Anum_pg_class_relowner,
442 Anum_pg_class_relacl,
443 OBJECT_TABLE,
444 true
447 "tablespace",
448 TableSpaceRelationId,
449 TablespaceOidIndexId,
450 TABLESPACEOID,
452 Anum_pg_tablespace_oid,
453 Anum_pg_tablespace_spcname,
454 InvalidAttrNumber,
455 Anum_pg_tablespace_spcowner,
456 Anum_pg_tablespace_spcacl,
457 OBJECT_TABLESPACE,
458 true
461 "transform",
462 TransformRelationId,
463 TransformOidIndexId,
464 TRFOID,
465 InvalidAttrNumber,
466 Anum_pg_transform_oid
469 "trigger",
470 TriggerRelationId,
471 TriggerOidIndexId,
474 Anum_pg_trigger_oid,
475 Anum_pg_trigger_tgname,
476 InvalidAttrNumber,
477 InvalidAttrNumber,
478 InvalidAttrNumber,
480 false
483 "policy",
484 PolicyRelationId,
485 PolicyOidIndexId,
488 Anum_pg_policy_oid,
489 Anum_pg_policy_polname,
490 InvalidAttrNumber,
491 InvalidAttrNumber,
492 InvalidAttrNumber,
494 false
497 "event trigger",
498 EventTriggerRelationId,
499 EventTriggerOidIndexId,
500 EVENTTRIGGEROID,
501 EVENTTRIGGERNAME,
502 Anum_pg_event_trigger_oid,
503 Anum_pg_event_trigger_evtname,
504 InvalidAttrNumber,
505 Anum_pg_event_trigger_evtowner,
506 InvalidAttrNumber,
507 OBJECT_EVENT_TRIGGER,
508 true
511 "text search configuration",
512 TSConfigRelationId,
513 TSConfigOidIndexId,
514 TSCONFIGOID,
515 TSCONFIGNAMENSP,
516 Anum_pg_ts_config_oid,
517 Anum_pg_ts_config_cfgname,
518 Anum_pg_ts_config_cfgnamespace,
519 Anum_pg_ts_config_cfgowner,
520 InvalidAttrNumber,
521 OBJECT_TSCONFIGURATION,
522 true
525 "text search dictionary",
526 TSDictionaryRelationId,
527 TSDictionaryOidIndexId,
528 TSDICTOID,
529 TSDICTNAMENSP,
530 Anum_pg_ts_dict_oid,
531 Anum_pg_ts_dict_dictname,
532 Anum_pg_ts_dict_dictnamespace,
533 Anum_pg_ts_dict_dictowner,
534 InvalidAttrNumber,
535 OBJECT_TSDICTIONARY,
536 true
539 "text search parser",
540 TSParserRelationId,
541 TSParserOidIndexId,
542 TSPARSEROID,
543 TSPARSERNAMENSP,
544 Anum_pg_ts_parser_oid,
545 Anum_pg_ts_parser_prsname,
546 Anum_pg_ts_parser_prsnamespace,
547 InvalidAttrNumber,
548 InvalidAttrNumber,
550 true
553 "text search template",
554 TSTemplateRelationId,
555 TSTemplateOidIndexId,
556 TSTEMPLATEOID,
557 TSTEMPLATENAMENSP,
558 Anum_pg_ts_template_oid,
559 Anum_pg_ts_template_tmplname,
560 Anum_pg_ts_template_tmplnamespace,
561 InvalidAttrNumber,
562 InvalidAttrNumber,
564 true,
567 "type",
568 TypeRelationId,
569 TypeOidIndexId,
570 TYPEOID,
571 TYPENAMENSP,
572 Anum_pg_type_oid,
573 Anum_pg_type_typname,
574 Anum_pg_type_typnamespace,
575 Anum_pg_type_typowner,
576 Anum_pg_type_typacl,
577 OBJECT_TYPE,
578 true
581 "publication",
582 PublicationRelationId,
583 PublicationObjectIndexId,
584 PUBLICATIONOID,
585 PUBLICATIONNAME,
586 Anum_pg_publication_oid,
587 Anum_pg_publication_pubname,
588 InvalidAttrNumber,
589 Anum_pg_publication_pubowner,
590 InvalidAttrNumber,
591 OBJECT_PUBLICATION,
592 true
595 "subscription",
596 SubscriptionRelationId,
597 SubscriptionObjectIndexId,
598 SUBSCRIPTIONOID,
599 SUBSCRIPTIONNAME,
600 Anum_pg_subscription_oid,
601 Anum_pg_subscription_subname,
602 InvalidAttrNumber,
603 Anum_pg_subscription_subowner,
604 InvalidAttrNumber,
605 OBJECT_SUBSCRIPTION,
606 true
609 "extended statistics",
610 StatisticExtRelationId,
611 StatisticExtOidIndexId,
612 STATEXTOID,
613 STATEXTNAMENSP,
614 Anum_pg_statistic_ext_oid,
615 Anum_pg_statistic_ext_stxname,
616 Anum_pg_statistic_ext_stxnamespace,
617 Anum_pg_statistic_ext_stxowner,
618 InvalidAttrNumber, /* no ACL (same as relation) */
619 OBJECT_STATISTIC_EXT,
620 true
623 "user mapping",
624 UserMappingRelationId,
625 UserMappingOidIndexId,
626 USERMAPPINGOID,
628 Anum_pg_user_mapping_oid,
629 InvalidAttrNumber,
630 InvalidAttrNumber,
631 InvalidAttrNumber,
632 InvalidAttrNumber,
633 OBJECT_USER_MAPPING,
634 false
639 * This struct maps the string object types as returned by
640 * getObjectTypeDescription into ObjectType enum values. Note that some enum
641 * values can be obtained by different names, and that some string object types
642 * do not have corresponding values in the output enum. The user of this map
643 * must be careful to test for invalid values being returned.
645 * To ease maintenance, this follows the order of getObjectTypeDescription.
647 static const struct object_type_map
649 const char *tm_name;
650 ObjectType tm_type;
653 ObjectTypeMap[] =
655 /* OCLASS_CLASS, all kinds of relations */
657 "table", OBJECT_TABLE
660 "index", OBJECT_INDEX
663 "sequence", OBJECT_SEQUENCE
666 "toast table", -1
667 }, /* unmapped */
669 "view", OBJECT_VIEW
672 "materialized view", OBJECT_MATVIEW
675 "composite type", -1
676 }, /* unmapped */
678 "foreign table", OBJECT_FOREIGN_TABLE
681 "table column", OBJECT_COLUMN
684 "index column", -1
685 }, /* unmapped */
687 "sequence column", -1
688 }, /* unmapped */
690 "toast table column", -1
691 }, /* unmapped */
693 "view column", -1
694 }, /* unmapped */
696 "materialized view column", -1
697 }, /* unmapped */
699 "composite type column", -1
700 }, /* unmapped */
702 "foreign table column", OBJECT_COLUMN
704 /* OCLASS_PROC */
706 "aggregate", OBJECT_AGGREGATE
709 "function", OBJECT_FUNCTION
712 "procedure", OBJECT_PROCEDURE
714 /* OCLASS_TYPE */
716 "type", OBJECT_TYPE
718 /* OCLASS_CAST */
720 "cast", OBJECT_CAST
722 /* OCLASS_COLLATION */
724 "collation", OBJECT_COLLATION
726 /* OCLASS_CONSTRAINT */
728 "table constraint", OBJECT_TABCONSTRAINT
731 "domain constraint", OBJECT_DOMCONSTRAINT
733 /* OCLASS_CONVERSION */
735 "conversion", OBJECT_CONVERSION
737 /* OCLASS_DEFAULT */
739 "default value", OBJECT_DEFAULT
741 /* OCLASS_LANGUAGE */
743 "language", OBJECT_LANGUAGE
745 /* OCLASS_LARGEOBJECT */
747 "large object", OBJECT_LARGEOBJECT
749 /* OCLASS_OPERATOR */
751 "operator", OBJECT_OPERATOR
753 /* OCLASS_OPCLASS */
755 "operator class", OBJECT_OPCLASS
757 /* OCLASS_OPFAMILY */
759 "operator family", OBJECT_OPFAMILY
761 /* OCLASS_AM */
763 "access method", OBJECT_ACCESS_METHOD
765 /* OCLASS_AMOP */
767 "operator of access method", OBJECT_AMOP
769 /* OCLASS_AMPROC */
771 "function of access method", OBJECT_AMPROC
773 /* OCLASS_REWRITE */
775 "rule", OBJECT_RULE
777 /* OCLASS_TRIGGER */
779 "trigger", OBJECT_TRIGGER
781 /* OCLASS_SCHEMA */
783 "schema", OBJECT_SCHEMA
785 /* OCLASS_TSPARSER */
787 "text search parser", OBJECT_TSPARSER
789 /* OCLASS_TSDICT */
791 "text search dictionary", OBJECT_TSDICTIONARY
793 /* OCLASS_TSTEMPLATE */
795 "text search template", OBJECT_TSTEMPLATE
797 /* OCLASS_TSCONFIG */
799 "text search configuration", OBJECT_TSCONFIGURATION
801 /* OCLASS_ROLE */
803 "role", OBJECT_ROLE
805 /* OCLASS_ROLE_MEMBERSHIP */
807 "role membership", -1 /* unmapped */
809 /* OCLASS_DATABASE */
811 "database", OBJECT_DATABASE
813 /* OCLASS_TBLSPACE */
815 "tablespace", OBJECT_TABLESPACE
817 /* OCLASS_FDW */
819 "foreign-data wrapper", OBJECT_FDW
821 /* OCLASS_FOREIGN_SERVER */
823 "server", OBJECT_FOREIGN_SERVER
825 /* OCLASS_USER_MAPPING */
827 "user mapping", OBJECT_USER_MAPPING
829 /* OCLASS_DEFACL */
831 "default acl", OBJECT_DEFACL
833 /* OCLASS_EXTENSION */
835 "extension", OBJECT_EXTENSION
837 /* OCLASS_EVENT_TRIGGER */
839 "event trigger", OBJECT_EVENT_TRIGGER
841 /* OCLASS_PARAMETER_ACL */
843 "parameter ACL", OBJECT_PARAMETER_ACL
845 /* OCLASS_POLICY */
847 "policy", OBJECT_POLICY
849 /* OCLASS_PUBLICATION */
851 "publication", OBJECT_PUBLICATION
853 /* OCLASS_PUBLICATION_NAMESPACE */
855 "publication namespace", OBJECT_PUBLICATION_NAMESPACE
857 /* OCLASS_PUBLICATION_REL */
859 "publication relation", OBJECT_PUBLICATION_REL
861 /* OCLASS_SUBSCRIPTION */
863 "subscription", OBJECT_SUBSCRIPTION
865 /* OCLASS_TRANSFORM */
867 "transform", OBJECT_TRANSFORM
869 /* OCLASS_STATISTIC_EXT */
871 "statistics object", OBJECT_STATISTIC_EXT
875 const ObjectAddress InvalidObjectAddress =
877 InvalidOid,
878 InvalidOid,
882 static ObjectAddress get_object_address_unqualified(ObjectType objtype,
883 String *strval, bool missing_ok);
884 static ObjectAddress get_relation_by_qualified_name(ObjectType objtype,
885 List *object, Relation *relp,
886 LOCKMODE lockmode, bool missing_ok);
887 static ObjectAddress get_object_address_relobject(ObjectType objtype,
888 List *object, Relation *relp, bool missing_ok);
889 static ObjectAddress get_object_address_attribute(ObjectType objtype,
890 List *object, Relation *relp,
891 LOCKMODE lockmode, bool missing_ok);
892 static ObjectAddress get_object_address_attrdef(ObjectType objtype,
893 List *object, Relation *relp, LOCKMODE lockmode,
894 bool missing_ok);
895 static ObjectAddress get_object_address_type(ObjectType objtype,
896 TypeName *typename, bool missing_ok);
897 static ObjectAddress get_object_address_opcf(ObjectType objtype, List *object,
898 bool missing_ok);
899 static ObjectAddress get_object_address_opf_member(ObjectType objtype,
900 List *object, bool missing_ok);
902 static ObjectAddress get_object_address_usermapping(List *object,
903 bool missing_ok);
904 static ObjectAddress get_object_address_publication_rel(List *object,
905 Relation *relp,
906 bool missing_ok);
907 static ObjectAddress get_object_address_publication_schema(List *object,
908 bool missing_ok);
909 static ObjectAddress get_object_address_defacl(List *object,
910 bool missing_ok);
911 static const ObjectPropertyType *get_object_property_data(Oid class_id);
913 static void getRelationDescription(StringInfo buffer, Oid relid,
914 bool missing_ok);
915 static void getOpFamilyDescription(StringInfo buffer, Oid opfid,
916 bool missing_ok);
917 static void getRelationTypeDescription(StringInfo buffer, Oid relid,
918 int32 objectSubId, bool missing_ok);
919 static void getProcedureTypeDescription(StringInfo buffer, Oid procid,
920 bool missing_ok);
921 static void getConstraintTypeDescription(StringInfo buffer, Oid constroid,
922 bool missing_ok);
923 static void getOpFamilyIdentity(StringInfo buffer, Oid opfid, List **object,
924 bool missing_ok);
925 static void getRelationIdentity(StringInfo buffer, Oid relid, List **object,
926 bool missing_ok);
929 * Translate an object name and arguments (as passed by the parser) to an
930 * ObjectAddress.
932 * The returned object will be locked using the specified lockmode. If a
933 * sub-object is looked up, the parent object will be locked instead.
935 * If the object is a relation or a child object of a relation (e.g. an
936 * attribute or constraint), the relation is also opened and *relp receives
937 * the open relcache entry pointer; otherwise, *relp is set to NULL. This
938 * is a bit grotty but it makes life simpler, since the caller will
939 * typically need the relcache entry too. Caller must close the relcache
940 * entry when done with it. The relation is locked with the specified lockmode
941 * if the target object is the relation itself or an attribute, but for other
942 * child objects, only AccessShareLock is acquired on the relation.
944 * If the object is not found, an error is thrown, unless missing_ok is
945 * true. In this case, no lock is acquired, relp is set to NULL, and the
946 * returned address has objectId set to InvalidOid.
948 * We don't currently provide a function to release the locks acquired here;
949 * typically, the lock must be held until commit to guard against a concurrent
950 * drop operation.
952 * Note: If the object is not found, we don't give any indication of the
953 * reason. (It might have been a missing schema if the name was qualified, or
954 * a nonexistent type name in case of a cast, function or operator; etc).
955 * Currently there is only one caller that might be interested in such info, so
956 * we don't spend much effort here. If more callers start to care, it might be
957 * better to add some support for that in this function.
959 ObjectAddress
960 get_object_address(ObjectType objtype, Node *object,
961 Relation *relp, LOCKMODE lockmode, bool missing_ok)
963 ObjectAddress address;
964 ObjectAddress old_address = {InvalidOid, InvalidOid, 0};
965 Relation relation = NULL;
966 uint64 inval_count;
968 /* Some kind of lock must be taken. */
969 Assert(lockmode != NoLock);
971 for (;;)
974 * Remember this value, so that, after looking up the object name and
975 * locking it, we can check whether any invalidation messages have
976 * been processed that might require a do-over.
978 inval_count = SharedInvalidMessageCounter;
980 /* Look up object address. */
981 switch (objtype)
983 case OBJECT_INDEX:
984 case OBJECT_SEQUENCE:
985 case OBJECT_TABLE:
986 case OBJECT_VIEW:
987 case OBJECT_MATVIEW:
988 case OBJECT_FOREIGN_TABLE:
989 address =
990 get_relation_by_qualified_name(objtype, castNode(List, object),
991 &relation, lockmode,
992 missing_ok);
993 break;
994 case OBJECT_COLUMN:
995 address =
996 get_object_address_attribute(objtype, castNode(List, object),
997 &relation, lockmode,
998 missing_ok);
999 break;
1000 case OBJECT_DEFAULT:
1001 address =
1002 get_object_address_attrdef(objtype, castNode(List, object),
1003 &relation, lockmode,
1004 missing_ok);
1005 break;
1006 case OBJECT_RULE:
1007 case OBJECT_TRIGGER:
1008 case OBJECT_TABCONSTRAINT:
1009 case OBJECT_POLICY:
1010 address = get_object_address_relobject(objtype, castNode(List, object),
1011 &relation, missing_ok);
1012 break;
1013 case OBJECT_DOMCONSTRAINT:
1015 List *objlist;
1016 ObjectAddress domaddr;
1017 char *constrname;
1019 objlist = castNode(List, object);
1020 domaddr = get_object_address_type(OBJECT_DOMAIN,
1021 linitial_node(TypeName, objlist),
1022 missing_ok);
1023 constrname = strVal(lsecond(objlist));
1025 address.classId = ConstraintRelationId;
1026 address.objectId = get_domain_constraint_oid(domaddr.objectId,
1027 constrname, missing_ok);
1028 address.objectSubId = 0;
1030 break;
1031 case OBJECT_DATABASE:
1032 case OBJECT_EXTENSION:
1033 case OBJECT_TABLESPACE:
1034 case OBJECT_ROLE:
1035 case OBJECT_SCHEMA:
1036 case OBJECT_LANGUAGE:
1037 case OBJECT_FDW:
1038 case OBJECT_FOREIGN_SERVER:
1039 case OBJECT_EVENT_TRIGGER:
1040 case OBJECT_PARAMETER_ACL:
1041 case OBJECT_ACCESS_METHOD:
1042 case OBJECT_PUBLICATION:
1043 case OBJECT_SUBSCRIPTION:
1044 address = get_object_address_unqualified(objtype,
1045 castNode(String, object), missing_ok);
1046 break;
1047 case OBJECT_TYPE:
1048 case OBJECT_DOMAIN:
1049 address = get_object_address_type(objtype, castNode(TypeName, object), missing_ok);
1050 break;
1051 case OBJECT_AGGREGATE:
1052 case OBJECT_FUNCTION:
1053 case OBJECT_PROCEDURE:
1054 case OBJECT_ROUTINE:
1055 address.classId = ProcedureRelationId;
1056 address.objectId = LookupFuncWithArgs(objtype, castNode(ObjectWithArgs, object), missing_ok);
1057 address.objectSubId = 0;
1058 break;
1059 case OBJECT_OPERATOR:
1060 address.classId = OperatorRelationId;
1061 address.objectId = LookupOperWithArgs(castNode(ObjectWithArgs, object), missing_ok);
1062 address.objectSubId = 0;
1063 break;
1064 case OBJECT_COLLATION:
1065 address.classId = CollationRelationId;
1066 address.objectId = get_collation_oid(castNode(List, object), missing_ok);
1067 address.objectSubId = 0;
1068 break;
1069 case OBJECT_CONVERSION:
1070 address.classId = ConversionRelationId;
1071 address.objectId = get_conversion_oid(castNode(List, object), missing_ok);
1072 address.objectSubId = 0;
1073 break;
1074 case OBJECT_OPCLASS:
1075 case OBJECT_OPFAMILY:
1076 address = get_object_address_opcf(objtype, castNode(List, object), missing_ok);
1077 break;
1078 case OBJECT_AMOP:
1079 case OBJECT_AMPROC:
1080 address = get_object_address_opf_member(objtype, castNode(List, object), missing_ok);
1081 break;
1082 case OBJECT_LARGEOBJECT:
1083 address.classId = LargeObjectRelationId;
1084 address.objectId = oidparse(object);
1085 address.objectSubId = 0;
1086 if (!LargeObjectExists(address.objectId))
1088 if (!missing_ok)
1089 ereport(ERROR,
1090 (errcode(ERRCODE_UNDEFINED_OBJECT),
1091 errmsg("large object %u does not exist",
1092 address.objectId)));
1094 break;
1095 case OBJECT_CAST:
1097 TypeName *sourcetype = linitial_node(TypeName, castNode(List, object));
1098 TypeName *targettype = lsecond_node(TypeName, castNode(List, object));
1099 Oid sourcetypeid;
1100 Oid targettypeid;
1102 sourcetypeid = LookupTypeNameOid(NULL, sourcetype, missing_ok);
1103 targettypeid = LookupTypeNameOid(NULL, targettype, missing_ok);
1104 address.classId = CastRelationId;
1105 address.objectId =
1106 get_cast_oid(sourcetypeid, targettypeid, missing_ok);
1107 address.objectSubId = 0;
1109 break;
1110 case OBJECT_TRANSFORM:
1112 TypeName *typename = linitial_node(TypeName, castNode(List, object));
1113 char *langname = strVal(lsecond(castNode(List, object)));
1114 Oid type_id = LookupTypeNameOid(NULL, typename, missing_ok);
1115 Oid lang_id = get_language_oid(langname, missing_ok);
1117 address.classId = TransformRelationId;
1118 address.objectId =
1119 get_transform_oid(type_id, lang_id, missing_ok);
1120 address.objectSubId = 0;
1122 break;
1123 case OBJECT_TSPARSER:
1124 address.classId = TSParserRelationId;
1125 address.objectId = get_ts_parser_oid(castNode(List, object), missing_ok);
1126 address.objectSubId = 0;
1127 break;
1128 case OBJECT_TSDICTIONARY:
1129 address.classId = TSDictionaryRelationId;
1130 address.objectId = get_ts_dict_oid(castNode(List, object), missing_ok);
1131 address.objectSubId = 0;
1132 break;
1133 case OBJECT_TSTEMPLATE:
1134 address.classId = TSTemplateRelationId;
1135 address.objectId = get_ts_template_oid(castNode(List, object), missing_ok);
1136 address.objectSubId = 0;
1137 break;
1138 case OBJECT_TSCONFIGURATION:
1139 address.classId = TSConfigRelationId;
1140 address.objectId = get_ts_config_oid(castNode(List, object), missing_ok);
1141 address.objectSubId = 0;
1142 break;
1143 case OBJECT_USER_MAPPING:
1144 address = get_object_address_usermapping(castNode(List, object),
1145 missing_ok);
1146 break;
1147 case OBJECT_PUBLICATION_NAMESPACE:
1148 address = get_object_address_publication_schema(castNode(List, object),
1149 missing_ok);
1150 break;
1151 case OBJECT_PUBLICATION_REL:
1152 address = get_object_address_publication_rel(castNode(List, object),
1153 &relation,
1154 missing_ok);
1155 break;
1156 case OBJECT_DEFACL:
1157 address = get_object_address_defacl(castNode(List, object),
1158 missing_ok);
1159 break;
1160 case OBJECT_STATISTIC_EXT:
1161 address.classId = StatisticExtRelationId;
1162 address.objectId = get_statistics_object_oid(castNode(List, object),
1163 missing_ok);
1164 address.objectSubId = 0;
1165 break;
1166 default:
1167 elog(ERROR, "unrecognized object type: %d", (int) objtype);
1168 /* placate compiler, in case it thinks elog might return */
1169 address.classId = InvalidOid;
1170 address.objectId = InvalidOid;
1171 address.objectSubId = 0;
1175 * If we could not find the supplied object, return without locking.
1177 if (!OidIsValid(address.objectId))
1179 Assert(missing_ok);
1180 return address;
1184 * If we're retrying, see if we got the same answer as last time. If
1185 * so, we're done; if not, we locked the wrong thing, so give up our
1186 * lock.
1188 if (OidIsValid(old_address.classId))
1190 if (old_address.classId == address.classId
1191 && old_address.objectId == address.objectId
1192 && old_address.objectSubId == address.objectSubId)
1193 break;
1194 if (old_address.classId != RelationRelationId)
1196 if (IsSharedRelation(old_address.classId))
1197 UnlockSharedObject(old_address.classId,
1198 old_address.objectId,
1199 0, lockmode);
1200 else
1201 UnlockDatabaseObject(old_address.classId,
1202 old_address.objectId,
1203 0, lockmode);
1208 * If we're dealing with a relation or attribute, then the relation is
1209 * already locked. Otherwise, we lock it now.
1211 if (address.classId != RelationRelationId)
1213 if (IsSharedRelation(address.classId))
1214 LockSharedObject(address.classId, address.objectId, 0,
1215 lockmode);
1216 else
1217 LockDatabaseObject(address.classId, address.objectId, 0,
1218 lockmode);
1222 * At this point, we've resolved the name to an OID and locked the
1223 * corresponding database object. However, it's possible that by the
1224 * time we acquire the lock on the object, concurrent DDL has modified
1225 * the database in such a way that the name we originally looked up no
1226 * longer resolves to that OID.
1228 * We can be certain that this isn't an issue if (a) no shared
1229 * invalidation messages have been processed or (b) we've locked a
1230 * relation somewhere along the line. All the relation name lookups
1231 * in this module ultimately use RangeVarGetRelid() to acquire a
1232 * relation lock, and that function protects against the same kinds of
1233 * races we're worried about here. Even when operating on a
1234 * constraint, rule, or trigger, we still acquire AccessShareLock on
1235 * the relation, which is enough to freeze out any concurrent DDL.
1237 * In all other cases, however, it's possible that the name we looked
1238 * up no longer refers to the object we locked, so we retry the lookup
1239 * and see whether we get the same answer.
1241 if (inval_count == SharedInvalidMessageCounter || relation != NULL)
1242 break;
1243 old_address = address;
1246 /* Return the object address and the relation. */
1247 *relp = relation;
1248 return address;
1252 * Return an ObjectAddress based on a RangeVar and an object name. The
1253 * name of the relation identified by the RangeVar is prepended to the
1254 * (possibly empty) list passed in as object. This is useful to find
1255 * the ObjectAddress of objects that depend on a relation. All other
1256 * considerations are exactly as for get_object_address above.
1258 ObjectAddress
1259 get_object_address_rv(ObjectType objtype, RangeVar *rel, List *object,
1260 Relation *relp, LOCKMODE lockmode,
1261 bool missing_ok)
1263 if (rel)
1265 object = lcons(makeString(rel->relname), object);
1266 if (rel->schemaname)
1267 object = lcons(makeString(rel->schemaname), object);
1268 if (rel->catalogname)
1269 object = lcons(makeString(rel->catalogname), object);
1272 return get_object_address(objtype, (Node *) object,
1273 relp, lockmode, missing_ok);
1277 * Find an ObjectAddress for a type of object that is identified by an
1278 * unqualified name.
1280 static ObjectAddress
1281 get_object_address_unqualified(ObjectType objtype,
1282 String *strval, bool missing_ok)
1284 const char *name;
1285 ObjectAddress address;
1287 name = strVal(strval);
1289 /* Translate name to OID. */
1290 switch (objtype)
1292 case OBJECT_ACCESS_METHOD:
1293 address.classId = AccessMethodRelationId;
1294 address.objectId = get_am_oid(name, missing_ok);
1295 address.objectSubId = 0;
1296 break;
1297 case OBJECT_DATABASE:
1298 address.classId = DatabaseRelationId;
1299 address.objectId = get_database_oid(name, missing_ok);
1300 address.objectSubId = 0;
1301 break;
1302 case OBJECT_EXTENSION:
1303 address.classId = ExtensionRelationId;
1304 address.objectId = get_extension_oid(name, missing_ok);
1305 address.objectSubId = 0;
1306 break;
1307 case OBJECT_TABLESPACE:
1308 address.classId = TableSpaceRelationId;
1309 address.objectId = get_tablespace_oid(name, missing_ok);
1310 address.objectSubId = 0;
1311 break;
1312 case OBJECT_ROLE:
1313 address.classId = AuthIdRelationId;
1314 address.objectId = get_role_oid(name, missing_ok);
1315 address.objectSubId = 0;
1316 break;
1317 case OBJECT_SCHEMA:
1318 address.classId = NamespaceRelationId;
1319 address.objectId = get_namespace_oid(name, missing_ok);
1320 address.objectSubId = 0;
1321 break;
1322 case OBJECT_LANGUAGE:
1323 address.classId = LanguageRelationId;
1324 address.objectId = get_language_oid(name, missing_ok);
1325 address.objectSubId = 0;
1326 break;
1327 case OBJECT_FDW:
1328 address.classId = ForeignDataWrapperRelationId;
1329 address.objectId = get_foreign_data_wrapper_oid(name, missing_ok);
1330 address.objectSubId = 0;
1331 break;
1332 case OBJECT_FOREIGN_SERVER:
1333 address.classId = ForeignServerRelationId;
1334 address.objectId = get_foreign_server_oid(name, missing_ok);
1335 address.objectSubId = 0;
1336 break;
1337 case OBJECT_EVENT_TRIGGER:
1338 address.classId = EventTriggerRelationId;
1339 address.objectId = get_event_trigger_oid(name, missing_ok);
1340 address.objectSubId = 0;
1341 break;
1342 case OBJECT_PARAMETER_ACL:
1343 address.classId = ParameterAclRelationId;
1344 address.objectId = ParameterAclLookup(name, missing_ok);
1345 address.objectSubId = 0;
1346 break;
1347 case OBJECT_PUBLICATION:
1348 address.classId = PublicationRelationId;
1349 address.objectId = get_publication_oid(name, missing_ok);
1350 address.objectSubId = 0;
1351 break;
1352 case OBJECT_SUBSCRIPTION:
1353 address.classId = SubscriptionRelationId;
1354 address.objectId = get_subscription_oid(name, missing_ok);
1355 address.objectSubId = 0;
1356 break;
1357 default:
1358 elog(ERROR, "unrecognized object type: %d", (int) objtype);
1359 /* placate compiler, which doesn't know elog won't return */
1360 address.classId = InvalidOid;
1361 address.objectId = InvalidOid;
1362 address.objectSubId = 0;
1365 return address;
1369 * Locate a relation by qualified name.
1371 static ObjectAddress
1372 get_relation_by_qualified_name(ObjectType objtype, List *object,
1373 Relation *relp, LOCKMODE lockmode,
1374 bool missing_ok)
1376 Relation relation;
1377 ObjectAddress address;
1379 address.classId = RelationRelationId;
1380 address.objectId = InvalidOid;
1381 address.objectSubId = 0;
1383 relation = relation_openrv_extended(makeRangeVarFromNameList(object),
1384 lockmode, missing_ok);
1385 if (!relation)
1386 return address;
1388 switch (objtype)
1390 case OBJECT_INDEX:
1391 if (relation->rd_rel->relkind != RELKIND_INDEX &&
1392 relation->rd_rel->relkind != RELKIND_PARTITIONED_INDEX)
1393 ereport(ERROR,
1394 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1395 errmsg("\"%s\" is not an index",
1396 RelationGetRelationName(relation))));
1397 break;
1398 case OBJECT_SEQUENCE:
1399 if (relation->rd_rel->relkind != RELKIND_SEQUENCE)
1400 ereport(ERROR,
1401 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1402 errmsg("\"%s\" is not a sequence",
1403 RelationGetRelationName(relation))));
1404 break;
1405 case OBJECT_TABLE:
1406 if (relation->rd_rel->relkind != RELKIND_RELATION &&
1407 relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
1408 ereport(ERROR,
1409 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1410 errmsg("\"%s\" is not a table",
1411 RelationGetRelationName(relation))));
1412 break;
1413 case OBJECT_VIEW:
1414 if (relation->rd_rel->relkind != RELKIND_VIEW)
1415 ereport(ERROR,
1416 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1417 errmsg("\"%s\" is not a view",
1418 RelationGetRelationName(relation))));
1419 break;
1420 case OBJECT_MATVIEW:
1421 if (relation->rd_rel->relkind != RELKIND_MATVIEW)
1422 ereport(ERROR,
1423 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1424 errmsg("\"%s\" is not a materialized view",
1425 RelationGetRelationName(relation))));
1426 break;
1427 case OBJECT_FOREIGN_TABLE:
1428 if (relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE)
1429 ereport(ERROR,
1430 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1431 errmsg("\"%s\" is not a foreign table",
1432 RelationGetRelationName(relation))));
1433 break;
1434 default:
1435 elog(ERROR, "unrecognized object type: %d", (int) objtype);
1436 break;
1439 /* Done. */
1440 address.objectId = RelationGetRelid(relation);
1441 *relp = relation;
1443 return address;
1447 * Find object address for an object that is attached to a relation.
1449 * Note that we take only an AccessShareLock on the relation. We need not
1450 * pass down the LOCKMODE from get_object_address(), because that is the lock
1451 * mode for the object itself, not the relation to which it is attached.
1453 static ObjectAddress
1454 get_object_address_relobject(ObjectType objtype, List *object,
1455 Relation *relp, bool missing_ok)
1457 ObjectAddress address;
1458 Relation relation = NULL;
1459 int nnames;
1460 const char *depname;
1461 List *relname;
1462 Oid reloid;
1464 /* Extract name of dependent object. */
1465 depname = strVal(llast(object));
1467 /* Separate relation name from dependent object name. */
1468 nnames = list_length(object);
1469 if (nnames < 2)
1470 ereport(ERROR,
1471 (errcode(ERRCODE_SYNTAX_ERROR),
1472 errmsg("must specify relation and object name")));
1474 /* Extract relation name and open relation. */
1475 relname = list_copy_head(object, nnames - 1);
1476 relation = table_openrv_extended(makeRangeVarFromNameList(relname),
1477 AccessShareLock,
1478 missing_ok);
1480 reloid = relation ? RelationGetRelid(relation) : InvalidOid;
1482 switch (objtype)
1484 case OBJECT_RULE:
1485 address.classId = RewriteRelationId;
1486 address.objectId = relation ?
1487 get_rewrite_oid(reloid, depname, missing_ok) : InvalidOid;
1488 address.objectSubId = 0;
1489 break;
1490 case OBJECT_TRIGGER:
1491 address.classId = TriggerRelationId;
1492 address.objectId = relation ?
1493 get_trigger_oid(reloid, depname, missing_ok) : InvalidOid;
1494 address.objectSubId = 0;
1495 break;
1496 case OBJECT_TABCONSTRAINT:
1497 address.classId = ConstraintRelationId;
1498 address.objectId = relation ?
1499 get_relation_constraint_oid(reloid, depname, missing_ok) :
1500 InvalidOid;
1501 address.objectSubId = 0;
1502 break;
1503 case OBJECT_POLICY:
1504 address.classId = PolicyRelationId;
1505 address.objectId = relation ?
1506 get_relation_policy_oid(reloid, depname, missing_ok) :
1507 InvalidOid;
1508 address.objectSubId = 0;
1509 break;
1510 default:
1511 elog(ERROR, "unrecognized object type: %d", (int) objtype);
1514 /* Avoid relcache leak when object not found. */
1515 if (!OidIsValid(address.objectId))
1517 if (relation != NULL)
1518 table_close(relation, AccessShareLock);
1520 relation = NULL; /* department of accident prevention */
1521 return address;
1524 /* Done. */
1525 *relp = relation;
1526 return address;
1530 * Find the ObjectAddress for an attribute.
1532 static ObjectAddress
1533 get_object_address_attribute(ObjectType objtype, List *object,
1534 Relation *relp, LOCKMODE lockmode,
1535 bool missing_ok)
1537 ObjectAddress address;
1538 List *relname;
1539 Oid reloid;
1540 Relation relation;
1541 const char *attname;
1542 AttrNumber attnum;
1544 /* Extract relation name and open relation. */
1545 if (list_length(object) < 2)
1546 ereport(ERROR,
1547 (errcode(ERRCODE_SYNTAX_ERROR),
1548 errmsg("column name must be qualified")));
1549 attname = strVal(llast(object));
1550 relname = list_copy_head(object, list_length(object) - 1);
1551 /* XXX no missing_ok support here */
1552 relation = relation_openrv(makeRangeVarFromNameList(relname), lockmode);
1553 reloid = RelationGetRelid(relation);
1555 /* Look up attribute and construct return value. */
1556 attnum = get_attnum(reloid, attname);
1557 if (attnum == InvalidAttrNumber)
1559 if (!missing_ok)
1560 ereport(ERROR,
1561 (errcode(ERRCODE_UNDEFINED_COLUMN),
1562 errmsg("column \"%s\" of relation \"%s\" does not exist",
1563 attname, NameListToString(relname))));
1565 address.classId = RelationRelationId;
1566 address.objectId = InvalidOid;
1567 address.objectSubId = InvalidAttrNumber;
1568 relation_close(relation, lockmode);
1569 return address;
1572 address.classId = RelationRelationId;
1573 address.objectId = reloid;
1574 address.objectSubId = attnum;
1576 *relp = relation;
1577 return address;
1581 * Find the ObjectAddress for an attribute's default value.
1583 static ObjectAddress
1584 get_object_address_attrdef(ObjectType objtype, List *object,
1585 Relation *relp, LOCKMODE lockmode,
1586 bool missing_ok)
1588 ObjectAddress address;
1589 List *relname;
1590 Oid reloid;
1591 Relation relation;
1592 const char *attname;
1593 AttrNumber attnum;
1594 TupleDesc tupdesc;
1595 Oid defoid;
1597 /* Extract relation name and open relation. */
1598 if (list_length(object) < 2)
1599 ereport(ERROR,
1600 (errcode(ERRCODE_SYNTAX_ERROR),
1601 errmsg("column name must be qualified")));
1602 attname = strVal(llast(object));
1603 relname = list_copy_head(object, list_length(object) - 1);
1604 /* XXX no missing_ok support here */
1605 relation = relation_openrv(makeRangeVarFromNameList(relname), lockmode);
1606 reloid = RelationGetRelid(relation);
1608 tupdesc = RelationGetDescr(relation);
1610 /* Look up attribute number and fetch the pg_attrdef OID */
1611 attnum = get_attnum(reloid, attname);
1612 defoid = InvalidOid;
1613 if (attnum != InvalidAttrNumber && tupdesc->constr != NULL)
1614 defoid = GetAttrDefaultOid(reloid, attnum);
1615 if (!OidIsValid(defoid))
1617 if (!missing_ok)
1618 ereport(ERROR,
1619 (errcode(ERRCODE_UNDEFINED_COLUMN),
1620 errmsg("default value for column \"%s\" of relation \"%s\" does not exist",
1621 attname, NameListToString(relname))));
1623 address.classId = AttrDefaultRelationId;
1624 address.objectId = InvalidOid;
1625 address.objectSubId = InvalidAttrNumber;
1626 relation_close(relation, lockmode);
1627 return address;
1630 address.classId = AttrDefaultRelationId;
1631 address.objectId = defoid;
1632 address.objectSubId = 0;
1634 *relp = relation;
1635 return address;
1639 * Find the ObjectAddress for a type or domain
1641 static ObjectAddress
1642 get_object_address_type(ObjectType objtype, TypeName *typename, bool missing_ok)
1644 ObjectAddress address;
1645 Type tup;
1647 address.classId = TypeRelationId;
1648 address.objectId = InvalidOid;
1649 address.objectSubId = 0;
1651 tup = LookupTypeName(NULL, typename, NULL, missing_ok);
1652 if (!HeapTupleIsValid(tup))
1654 if (!missing_ok)
1655 ereport(ERROR,
1656 (errcode(ERRCODE_UNDEFINED_OBJECT),
1657 errmsg("type \"%s\" does not exist",
1658 TypeNameToString(typename))));
1659 return address;
1661 address.objectId = typeTypeId(tup);
1663 if (objtype == OBJECT_DOMAIN)
1665 if (((Form_pg_type) GETSTRUCT(tup))->typtype != TYPTYPE_DOMAIN)
1666 ereport(ERROR,
1667 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1668 errmsg("\"%s\" is not a domain",
1669 TypeNameToString(typename))));
1672 ReleaseSysCache(tup);
1674 return address;
1678 * Find the ObjectAddress for an opclass or opfamily.
1680 static ObjectAddress
1681 get_object_address_opcf(ObjectType objtype, List *object, bool missing_ok)
1683 Oid amoid;
1684 ObjectAddress address;
1686 /* XXX no missing_ok support here */
1687 amoid = get_index_am_oid(strVal(linitial(object)), false);
1688 object = list_copy_tail(object, 1);
1690 switch (objtype)
1692 case OBJECT_OPCLASS:
1693 address.classId = OperatorClassRelationId;
1694 address.objectId = get_opclass_oid(amoid, object, missing_ok);
1695 address.objectSubId = 0;
1696 break;
1697 case OBJECT_OPFAMILY:
1698 address.classId = OperatorFamilyRelationId;
1699 address.objectId = get_opfamily_oid(amoid, object, missing_ok);
1700 address.objectSubId = 0;
1701 break;
1702 default:
1703 elog(ERROR, "unrecognized object type: %d", (int) objtype);
1704 /* placate compiler, which doesn't know elog won't return */
1705 address.classId = InvalidOid;
1706 address.objectId = InvalidOid;
1707 address.objectSubId = 0;
1710 return address;
1714 * Find the ObjectAddress for an opclass/opfamily member.
1716 * (The returned address corresponds to a pg_amop/pg_amproc object).
1718 static ObjectAddress
1719 get_object_address_opf_member(ObjectType objtype,
1720 List *object, bool missing_ok)
1722 ObjectAddress famaddr;
1723 ObjectAddress address;
1724 ListCell *cell;
1725 List *copy;
1726 TypeName *typenames[2];
1727 Oid typeoids[2];
1728 int membernum;
1729 int i;
1732 * The last element of the object list contains the strategy or procedure
1733 * number. We need to strip that out before getting the opclass/family
1734 * address. The rest can be used directly by get_object_address_opcf().
1736 membernum = atoi(strVal(llast(linitial(object))));
1737 copy = list_copy_head(linitial(object), list_length(linitial(object)) - 1);
1739 /* no missing_ok support here */
1740 famaddr = get_object_address_opcf(OBJECT_OPFAMILY, copy, false);
1742 /* find out left/right type names and OIDs */
1743 typenames[0] = typenames[1] = NULL;
1744 typeoids[0] = typeoids[1] = InvalidOid;
1745 i = 0;
1746 foreach(cell, lsecond(object))
1748 ObjectAddress typaddr;
1750 typenames[i] = lfirst_node(TypeName, cell);
1751 typaddr = get_object_address_type(OBJECT_TYPE, typenames[i], missing_ok);
1752 typeoids[i] = typaddr.objectId;
1753 if (++i >= 2)
1754 break;
1757 switch (objtype)
1759 case OBJECT_AMOP:
1761 HeapTuple tp;
1763 ObjectAddressSet(address, AccessMethodOperatorRelationId,
1764 InvalidOid);
1766 tp = SearchSysCache4(AMOPSTRATEGY,
1767 ObjectIdGetDatum(famaddr.objectId),
1768 ObjectIdGetDatum(typeoids[0]),
1769 ObjectIdGetDatum(typeoids[1]),
1770 Int16GetDatum(membernum));
1771 if (!HeapTupleIsValid(tp))
1773 if (!missing_ok)
1774 ereport(ERROR,
1775 (errcode(ERRCODE_UNDEFINED_OBJECT),
1776 errmsg("operator %d (%s, %s) of %s does not exist",
1777 membernum,
1778 TypeNameToString(typenames[0]),
1779 TypeNameToString(typenames[1]),
1780 getObjectDescription(&famaddr, false))));
1782 else
1784 address.objectId = ((Form_pg_amop) GETSTRUCT(tp))->oid;
1785 ReleaseSysCache(tp);
1788 break;
1790 case OBJECT_AMPROC:
1792 HeapTuple tp;
1794 ObjectAddressSet(address, AccessMethodProcedureRelationId,
1795 InvalidOid);
1797 tp = SearchSysCache4(AMPROCNUM,
1798 ObjectIdGetDatum(famaddr.objectId),
1799 ObjectIdGetDatum(typeoids[0]),
1800 ObjectIdGetDatum(typeoids[1]),
1801 Int16GetDatum(membernum));
1802 if (!HeapTupleIsValid(tp))
1804 if (!missing_ok)
1805 ereport(ERROR,
1806 (errcode(ERRCODE_UNDEFINED_OBJECT),
1807 errmsg("function %d (%s, %s) of %s does not exist",
1808 membernum,
1809 TypeNameToString(typenames[0]),
1810 TypeNameToString(typenames[1]),
1811 getObjectDescription(&famaddr, false))));
1813 else
1815 address.objectId = ((Form_pg_amproc) GETSTRUCT(tp))->oid;
1816 ReleaseSysCache(tp);
1819 break;
1820 default:
1821 elog(ERROR, "unrecognized object type: %d", (int) objtype);
1824 return address;
1828 * Find the ObjectAddress for a user mapping.
1830 static ObjectAddress
1831 get_object_address_usermapping(List *object, bool missing_ok)
1833 ObjectAddress address;
1834 Oid userid;
1835 char *username;
1836 char *servername;
1837 ForeignServer *server;
1838 HeapTuple tp;
1840 ObjectAddressSet(address, UserMappingRelationId, InvalidOid);
1842 /* fetch string names from input lists, for error messages */
1843 username = strVal(linitial(object));
1844 servername = strVal(lsecond(object));
1846 /* look up pg_authid OID of mapped user; InvalidOid if PUBLIC */
1847 if (strcmp(username, "public") == 0)
1848 userid = InvalidOid;
1849 else
1851 tp = SearchSysCache1(AUTHNAME,
1852 CStringGetDatum(username));
1853 if (!HeapTupleIsValid(tp))
1855 if (!missing_ok)
1856 ereport(ERROR,
1857 (errcode(ERRCODE_UNDEFINED_OBJECT),
1858 errmsg("user mapping for user \"%s\" on server \"%s\" does not exist",
1859 username, servername)));
1860 return address;
1862 userid = ((Form_pg_authid) GETSTRUCT(tp))->oid;
1863 ReleaseSysCache(tp);
1866 /* Now look up the pg_user_mapping tuple */
1867 server = GetForeignServerByName(servername, true);
1868 if (!server)
1870 if (!missing_ok)
1871 ereport(ERROR,
1872 (errcode(ERRCODE_UNDEFINED_OBJECT),
1873 errmsg("server \"%s\" does not exist", servername)));
1874 return address;
1876 tp = SearchSysCache2(USERMAPPINGUSERSERVER,
1877 ObjectIdGetDatum(userid),
1878 ObjectIdGetDatum(server->serverid));
1879 if (!HeapTupleIsValid(tp))
1881 if (!missing_ok)
1882 ereport(ERROR,
1883 (errcode(ERRCODE_UNDEFINED_OBJECT),
1884 errmsg("user mapping for user \"%s\" on server \"%s\" does not exist",
1885 username, servername)));
1886 return address;
1889 address.objectId = ((Form_pg_user_mapping) GETSTRUCT(tp))->oid;
1891 ReleaseSysCache(tp);
1893 return address;
1897 * Find the ObjectAddress for a publication relation. The first element of
1898 * the object parameter is the relation name, the second is the
1899 * publication name.
1901 static ObjectAddress
1902 get_object_address_publication_rel(List *object,
1903 Relation *relp, bool missing_ok)
1905 ObjectAddress address;
1906 Relation relation;
1907 List *relname;
1908 char *pubname;
1909 Publication *pub;
1911 ObjectAddressSet(address, PublicationRelRelationId, InvalidOid);
1913 relname = linitial(object);
1914 relation = relation_openrv_extended(makeRangeVarFromNameList(relname),
1915 AccessShareLock, missing_ok);
1916 if (!relation)
1917 return address;
1919 /* fetch publication name from input list */
1920 pubname = strVal(lsecond(object));
1922 /* Now look up the pg_publication tuple */
1923 pub = GetPublicationByName(pubname, missing_ok);
1924 if (!pub)
1926 relation_close(relation, AccessShareLock);
1927 return address;
1930 /* Find the publication relation mapping in syscache. */
1931 address.objectId =
1932 GetSysCacheOid2(PUBLICATIONRELMAP, Anum_pg_publication_rel_oid,
1933 ObjectIdGetDatum(RelationGetRelid(relation)),
1934 ObjectIdGetDatum(pub->oid));
1935 if (!OidIsValid(address.objectId))
1937 if (!missing_ok)
1938 ereport(ERROR,
1939 (errcode(ERRCODE_UNDEFINED_OBJECT),
1940 errmsg("publication relation \"%s\" in publication \"%s\" does not exist",
1941 RelationGetRelationName(relation), pubname)));
1942 relation_close(relation, AccessShareLock);
1943 return address;
1946 *relp = relation;
1947 return address;
1951 * Find the ObjectAddress for a publication schema. The first element of the
1952 * object parameter is the schema name, the second is the publication name.
1954 static ObjectAddress
1955 get_object_address_publication_schema(List *object, bool missing_ok)
1957 ObjectAddress address;
1958 Publication *pub;
1959 char *pubname;
1960 char *schemaname;
1961 Oid schemaid;
1963 ObjectAddressSet(address, PublicationNamespaceRelationId, InvalidOid);
1965 /* Fetch schema name and publication name from input list */
1966 schemaname = strVal(linitial(object));
1967 pubname = strVal(lsecond(object));
1969 schemaid = get_namespace_oid(schemaname, missing_ok);
1970 if (!OidIsValid(schemaid))
1971 return address;
1973 /* Now look up the pg_publication tuple */
1974 pub = GetPublicationByName(pubname, missing_ok);
1975 if (!pub)
1976 return address;
1978 /* Find the publication schema mapping in syscache */
1979 address.objectId =
1980 GetSysCacheOid2(PUBLICATIONNAMESPACEMAP,
1981 Anum_pg_publication_namespace_oid,
1982 ObjectIdGetDatum(schemaid),
1983 ObjectIdGetDatum(pub->oid));
1984 if (!OidIsValid(address.objectId) && !missing_ok)
1985 ereport(ERROR,
1986 (errcode(ERRCODE_UNDEFINED_OBJECT),
1987 errmsg("publication schema \"%s\" in publication \"%s\" does not exist",
1988 schemaname, pubname)));
1990 return address;
1994 * Find the ObjectAddress for a default ACL.
1996 static ObjectAddress
1997 get_object_address_defacl(List *object, bool missing_ok)
1999 HeapTuple tp;
2000 Oid userid;
2001 Oid schemaid;
2002 char *username;
2003 char *schema;
2004 char objtype;
2005 char *objtype_str;
2006 ObjectAddress address;
2008 ObjectAddressSet(address, DefaultAclRelationId, InvalidOid);
2011 * First figure out the textual attributes so that they can be used for
2012 * error reporting.
2014 username = strVal(lsecond(object));
2015 if (list_length(object) >= 3)
2016 schema = (char *) strVal(lthird(object));
2017 else
2018 schema = NULL;
2021 * Decode defaclobjtype. Only first char is considered; the rest of the
2022 * string, if any, is blissfully ignored.
2024 objtype = ((char *) strVal(linitial(object)))[0];
2025 switch (objtype)
2027 case DEFACLOBJ_RELATION:
2028 objtype_str = "tables";
2029 break;
2030 case DEFACLOBJ_SEQUENCE:
2031 objtype_str = "sequences";
2032 break;
2033 case DEFACLOBJ_FUNCTION:
2034 objtype_str = "functions";
2035 break;
2036 case DEFACLOBJ_TYPE:
2037 objtype_str = "types";
2038 break;
2039 case DEFACLOBJ_NAMESPACE:
2040 objtype_str = "schemas";
2041 break;
2042 default:
2043 ereport(ERROR,
2044 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2045 errmsg("unrecognized default ACL object type \"%c\"", objtype),
2046 errhint("Valid object types are \"%c\", \"%c\", \"%c\", \"%c\", \"%c\".",
2047 DEFACLOBJ_RELATION,
2048 DEFACLOBJ_SEQUENCE,
2049 DEFACLOBJ_FUNCTION,
2050 DEFACLOBJ_TYPE,
2051 DEFACLOBJ_NAMESPACE)));
2055 * Look up user ID. Behave as "default ACL not found" if the user doesn't
2056 * exist.
2058 tp = SearchSysCache1(AUTHNAME,
2059 CStringGetDatum(username));
2060 if (!HeapTupleIsValid(tp))
2061 goto not_found;
2062 userid = ((Form_pg_authid) GETSTRUCT(tp))->oid;
2063 ReleaseSysCache(tp);
2066 * If a schema name was given, look up its OID. If it doesn't exist,
2067 * behave as "default ACL not found".
2069 if (schema)
2071 schemaid = get_namespace_oid(schema, true);
2072 if (schemaid == InvalidOid)
2073 goto not_found;
2075 else
2076 schemaid = InvalidOid;
2078 /* Finally, look up the pg_default_acl object */
2079 tp = SearchSysCache3(DEFACLROLENSPOBJ,
2080 ObjectIdGetDatum(userid),
2081 ObjectIdGetDatum(schemaid),
2082 CharGetDatum(objtype));
2083 if (!HeapTupleIsValid(tp))
2084 goto not_found;
2086 address.objectId = ((Form_pg_default_acl) GETSTRUCT(tp))->oid;
2087 ReleaseSysCache(tp);
2089 return address;
2091 not_found:
2092 if (!missing_ok)
2094 if (schema)
2095 ereport(ERROR,
2096 (errcode(ERRCODE_UNDEFINED_OBJECT),
2097 errmsg("default ACL for user \"%s\" in schema \"%s\" on %s does not exist",
2098 username, schema, objtype_str)));
2099 else
2100 ereport(ERROR,
2101 (errcode(ERRCODE_UNDEFINED_OBJECT),
2102 errmsg("default ACL for user \"%s\" on %s does not exist",
2103 username, objtype_str)));
2105 return address;
2109 * Convert an array of TEXT into a List of string Values, as emitted by the
2110 * parser, which is what get_object_address uses as input.
2112 static List *
2113 textarray_to_strvaluelist(ArrayType *arr)
2115 Datum *elems;
2116 bool *nulls;
2117 int nelems;
2118 List *list = NIL;
2119 int i;
2121 deconstruct_array_builtin(arr, TEXTOID, &elems, &nulls, &nelems);
2123 for (i = 0; i < nelems; i++)
2125 if (nulls[i])
2126 ereport(ERROR,
2127 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2128 errmsg("name or argument lists may not contain nulls")));
2129 list = lappend(list, makeString(TextDatumGetCString(elems[i])));
2132 return list;
2136 * SQL-callable version of get_object_address
2138 Datum
2139 pg_get_object_address(PG_FUNCTION_ARGS)
2141 char *ttype = TextDatumGetCString(PG_GETARG_DATUM(0));
2142 ArrayType *namearr = PG_GETARG_ARRAYTYPE_P(1);
2143 ArrayType *argsarr = PG_GETARG_ARRAYTYPE_P(2);
2144 int itype;
2145 ObjectType type;
2146 List *name = NIL;
2147 TypeName *typename = NULL;
2148 List *args = NIL;
2149 Node *objnode = NULL;
2150 ObjectAddress addr;
2151 TupleDesc tupdesc;
2152 Datum values[3];
2153 bool nulls[3];
2154 HeapTuple htup;
2155 Relation relation;
2157 /* Decode object type, raise error if unknown */
2158 itype = read_objtype_from_string(ttype);
2159 if (itype < 0)
2160 ereport(ERROR,
2161 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2162 errmsg("unsupported object type \"%s\"", ttype)));
2163 type = (ObjectType) itype;
2166 * Convert the text array to the representation appropriate for the given
2167 * object type. Most use a simple string Values list, but there are some
2168 * exceptions.
2170 if (type == OBJECT_TYPE || type == OBJECT_DOMAIN || type == OBJECT_CAST ||
2171 type == OBJECT_TRANSFORM || type == OBJECT_DOMCONSTRAINT)
2173 Datum *elems;
2174 bool *nulls;
2175 int nelems;
2177 deconstruct_array_builtin(namearr, TEXTOID, &elems, &nulls, &nelems);
2178 if (nelems != 1)
2179 ereport(ERROR,
2180 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2181 errmsg("name list length must be exactly %d", 1)));
2182 if (nulls[0])
2183 ereport(ERROR,
2184 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2185 errmsg("name or argument lists may not contain nulls")));
2186 typename = typeStringToTypeName(TextDatumGetCString(elems[0]));
2188 else if (type == OBJECT_LARGEOBJECT)
2190 Datum *elems;
2191 bool *nulls;
2192 int nelems;
2194 deconstruct_array_builtin(namearr, TEXTOID, &elems, &nulls, &nelems);
2195 if (nelems != 1)
2196 ereport(ERROR,
2197 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2198 errmsg("name list length must be exactly %d", 1)));
2199 if (nulls[0])
2200 ereport(ERROR,
2201 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2202 errmsg("large object OID may not be null")));
2203 objnode = (Node *) makeFloat(TextDatumGetCString(elems[0]));
2205 else
2207 name = textarray_to_strvaluelist(namearr);
2208 if (name == NIL)
2209 ereport(ERROR,
2210 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2211 errmsg("name list length must be at least %d", 1)));
2215 * If args are given, decode them according to the object type.
2217 if (type == OBJECT_AGGREGATE ||
2218 type == OBJECT_FUNCTION ||
2219 type == OBJECT_PROCEDURE ||
2220 type == OBJECT_ROUTINE ||
2221 type == OBJECT_OPERATOR ||
2222 type == OBJECT_CAST ||
2223 type == OBJECT_AMOP ||
2224 type == OBJECT_AMPROC)
2226 /* in these cases, the args list must be of TypeName */
2227 Datum *elems;
2228 bool *nulls;
2229 int nelems;
2230 int i;
2232 deconstruct_array_builtin(argsarr, TEXTOID, &elems, &nulls, &nelems);
2234 args = NIL;
2235 for (i = 0; i < nelems; i++)
2237 if (nulls[i])
2238 ereport(ERROR,
2239 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2240 errmsg("name or argument lists may not contain nulls")));
2241 args = lappend(args,
2242 typeStringToTypeName(TextDatumGetCString(elems[i])));
2245 else
2247 /* For all other object types, use string Values */
2248 args = textarray_to_strvaluelist(argsarr);
2252 * get_object_address is pretty sensitive to the length of its input
2253 * lists; check that they're what it wants.
2255 switch (type)
2257 case OBJECT_PUBLICATION_NAMESPACE:
2258 case OBJECT_USER_MAPPING:
2259 if (list_length(name) != 1)
2260 ereport(ERROR,
2261 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2262 errmsg("name list length must be exactly %d", 1)));
2263 /* fall through to check args length */
2264 /* FALLTHROUGH */
2265 case OBJECT_DOMCONSTRAINT:
2266 case OBJECT_CAST:
2267 case OBJECT_PUBLICATION_REL:
2268 case OBJECT_DEFACL:
2269 case OBJECT_TRANSFORM:
2270 if (list_length(args) != 1)
2271 ereport(ERROR,
2272 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2273 errmsg("argument list length must be exactly %d", 1)));
2274 break;
2275 case OBJECT_OPFAMILY:
2276 case OBJECT_OPCLASS:
2277 if (list_length(name) < 2)
2278 ereport(ERROR,
2279 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2280 errmsg("name list length must be at least %d", 2)));
2281 break;
2282 case OBJECT_AMOP:
2283 case OBJECT_AMPROC:
2284 if (list_length(name) < 3)
2285 ereport(ERROR,
2286 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2287 errmsg("name list length must be at least %d", 3)));
2288 /* fall through to check args length */
2289 /* FALLTHROUGH */
2290 case OBJECT_OPERATOR:
2291 if (list_length(args) != 2)
2292 ereport(ERROR,
2293 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2294 errmsg("argument list length must be exactly %d", 2)));
2295 break;
2296 default:
2297 break;
2301 * Now build the Node type that get_object_address() expects for the given
2302 * type.
2304 switch (type)
2306 case OBJECT_TABLE:
2307 case OBJECT_SEQUENCE:
2308 case OBJECT_VIEW:
2309 case OBJECT_MATVIEW:
2310 case OBJECT_INDEX:
2311 case OBJECT_FOREIGN_TABLE:
2312 case OBJECT_COLUMN:
2313 case OBJECT_ATTRIBUTE:
2314 case OBJECT_COLLATION:
2315 case OBJECT_CONVERSION:
2316 case OBJECT_STATISTIC_EXT:
2317 case OBJECT_TSPARSER:
2318 case OBJECT_TSDICTIONARY:
2319 case OBJECT_TSTEMPLATE:
2320 case OBJECT_TSCONFIGURATION:
2321 case OBJECT_DEFAULT:
2322 case OBJECT_POLICY:
2323 case OBJECT_RULE:
2324 case OBJECT_TRIGGER:
2325 case OBJECT_TABCONSTRAINT:
2326 case OBJECT_OPCLASS:
2327 case OBJECT_OPFAMILY:
2328 objnode = (Node *) name;
2329 break;
2330 case OBJECT_ACCESS_METHOD:
2331 case OBJECT_DATABASE:
2332 case OBJECT_EVENT_TRIGGER:
2333 case OBJECT_EXTENSION:
2334 case OBJECT_FDW:
2335 case OBJECT_FOREIGN_SERVER:
2336 case OBJECT_LANGUAGE:
2337 case OBJECT_PARAMETER_ACL:
2338 case OBJECT_PUBLICATION:
2339 case OBJECT_ROLE:
2340 case OBJECT_SCHEMA:
2341 case OBJECT_SUBSCRIPTION:
2342 case OBJECT_TABLESPACE:
2343 if (list_length(name) != 1)
2344 ereport(ERROR,
2345 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2346 errmsg("name list length must be exactly %d", 1)));
2347 objnode = linitial(name);
2348 break;
2349 case OBJECT_TYPE:
2350 case OBJECT_DOMAIN:
2351 objnode = (Node *) typename;
2352 break;
2353 case OBJECT_CAST:
2354 case OBJECT_DOMCONSTRAINT:
2355 case OBJECT_TRANSFORM:
2356 objnode = (Node *) list_make2(typename, linitial(args));
2357 break;
2358 case OBJECT_PUBLICATION_REL:
2359 objnode = (Node *) list_make2(name, linitial(args));
2360 break;
2361 case OBJECT_PUBLICATION_NAMESPACE:
2362 case OBJECT_USER_MAPPING:
2363 objnode = (Node *) list_make2(linitial(name), linitial(args));
2364 break;
2365 case OBJECT_DEFACL:
2366 objnode = (Node *) lcons(linitial(args), name);
2367 break;
2368 case OBJECT_AMOP:
2369 case OBJECT_AMPROC:
2370 objnode = (Node *) list_make2(name, args);
2371 break;
2372 case OBJECT_FUNCTION:
2373 case OBJECT_PROCEDURE:
2374 case OBJECT_ROUTINE:
2375 case OBJECT_AGGREGATE:
2376 case OBJECT_OPERATOR:
2378 ObjectWithArgs *owa = makeNode(ObjectWithArgs);
2380 owa->objname = name;
2381 owa->objargs = args;
2382 objnode = (Node *) owa;
2383 break;
2385 case OBJECT_LARGEOBJECT:
2386 /* already handled above */
2387 break;
2388 /* no default, to let compiler warn about missing case */
2391 if (objnode == NULL)
2392 elog(ERROR, "unrecognized object type: %d", type);
2394 addr = get_object_address(type, objnode,
2395 &relation, AccessShareLock, false);
2397 /* We don't need the relcache entry, thank you very much */
2398 if (relation)
2399 relation_close(relation, AccessShareLock);
2401 tupdesc = CreateTemplateTupleDesc(3);
2402 TupleDescInitEntry(tupdesc, (AttrNumber) 1, "classid",
2403 OIDOID, -1, 0);
2404 TupleDescInitEntry(tupdesc, (AttrNumber) 2, "objid",
2405 OIDOID, -1, 0);
2406 TupleDescInitEntry(tupdesc, (AttrNumber) 3, "objsubid",
2407 INT4OID, -1, 0);
2408 tupdesc = BlessTupleDesc(tupdesc);
2410 values[0] = ObjectIdGetDatum(addr.classId);
2411 values[1] = ObjectIdGetDatum(addr.objectId);
2412 values[2] = Int32GetDatum(addr.objectSubId);
2413 nulls[0] = false;
2414 nulls[1] = false;
2415 nulls[2] = false;
2417 htup = heap_form_tuple(tupdesc, values, nulls);
2419 PG_RETURN_DATUM(HeapTupleGetDatum(htup));
2423 * Check ownership of an object previously identified by get_object_address.
2425 void
2426 check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address,
2427 Node *object, Relation relation)
2429 switch (objtype)
2431 case OBJECT_INDEX:
2432 case OBJECT_SEQUENCE:
2433 case OBJECT_TABLE:
2434 case OBJECT_VIEW:
2435 case OBJECT_MATVIEW:
2436 case OBJECT_FOREIGN_TABLE:
2437 case OBJECT_COLUMN:
2438 case OBJECT_RULE:
2439 case OBJECT_TRIGGER:
2440 case OBJECT_POLICY:
2441 case OBJECT_TABCONSTRAINT:
2442 if (!object_ownercheck(RelationRelationId, RelationGetRelid(relation), roleid))
2443 aclcheck_error(ACLCHECK_NOT_OWNER, objtype,
2444 RelationGetRelationName(relation));
2445 break;
2446 case OBJECT_TYPE:
2447 case OBJECT_DOMAIN:
2448 case OBJECT_ATTRIBUTE:
2449 if (!object_ownercheck(address.classId, address.objectId, roleid))
2450 aclcheck_error_type(ACLCHECK_NOT_OWNER, address.objectId);
2451 break;
2452 case OBJECT_DOMCONSTRAINT:
2454 HeapTuple tuple;
2455 Oid contypid;
2457 tuple = SearchSysCache1(CONSTROID,
2458 ObjectIdGetDatum(address.objectId));
2459 if (!HeapTupleIsValid(tuple))
2460 elog(ERROR, "constraint with OID %u does not exist",
2461 address.objectId);
2463 contypid = ((Form_pg_constraint) GETSTRUCT(tuple))->contypid;
2465 ReleaseSysCache(tuple);
2468 * Fallback to type ownership check in this case as this is
2469 * what domain constraints rely on.
2471 if (!object_ownercheck(TypeRelationId, contypid, roleid))
2472 aclcheck_error_type(ACLCHECK_NOT_OWNER, contypid);
2474 break;
2475 case OBJECT_AGGREGATE:
2476 case OBJECT_FUNCTION:
2477 case OBJECT_PROCEDURE:
2478 case OBJECT_ROUTINE:
2479 case OBJECT_OPERATOR:
2480 if (!object_ownercheck(address.classId, address.objectId, roleid))
2481 aclcheck_error(ACLCHECK_NOT_OWNER, objtype,
2482 NameListToString((castNode(ObjectWithArgs, object))->objname));
2483 break;
2484 case OBJECT_DATABASE:
2485 case OBJECT_EVENT_TRIGGER:
2486 case OBJECT_EXTENSION:
2487 case OBJECT_FDW:
2488 case OBJECT_FOREIGN_SERVER:
2489 case OBJECT_LANGUAGE:
2490 case OBJECT_PUBLICATION:
2491 case OBJECT_SCHEMA:
2492 case OBJECT_SUBSCRIPTION:
2493 case OBJECT_TABLESPACE:
2494 if (!object_ownercheck(address.classId, address.objectId, roleid))
2495 aclcheck_error(ACLCHECK_NOT_OWNER, objtype,
2496 strVal(object));
2497 break;
2498 case OBJECT_COLLATION:
2499 case OBJECT_CONVERSION:
2500 case OBJECT_OPCLASS:
2501 case OBJECT_OPFAMILY:
2502 case OBJECT_STATISTIC_EXT:
2503 case OBJECT_TSDICTIONARY:
2504 case OBJECT_TSCONFIGURATION:
2505 if (!object_ownercheck(address.classId, address.objectId, roleid))
2506 aclcheck_error(ACLCHECK_NOT_OWNER, objtype,
2507 NameListToString(castNode(List, object)));
2508 break;
2509 case OBJECT_LARGEOBJECT:
2510 if (!lo_compat_privileges &&
2511 !object_ownercheck(address.classId, address.objectId, roleid))
2512 ereport(ERROR,
2513 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2514 errmsg("must be owner of large object %u",
2515 address.objectId)));
2516 break;
2517 case OBJECT_CAST:
2519 /* We can only check permissions on the source/target types */
2520 TypeName *sourcetype = linitial_node(TypeName, castNode(List, object));
2521 TypeName *targettype = lsecond_node(TypeName, castNode(List, object));
2522 Oid sourcetypeid = typenameTypeId(NULL, sourcetype);
2523 Oid targettypeid = typenameTypeId(NULL, targettype);
2525 if (!object_ownercheck(TypeRelationId, sourcetypeid, roleid)
2526 && !object_ownercheck(TypeRelationId, targettypeid, roleid))
2527 ereport(ERROR,
2528 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2529 errmsg("must be owner of type %s or type %s",
2530 format_type_be(sourcetypeid),
2531 format_type_be(targettypeid))));
2533 break;
2534 case OBJECT_TRANSFORM:
2536 TypeName *typename = linitial_node(TypeName, castNode(List, object));
2537 Oid typeid = typenameTypeId(NULL, typename);
2539 if (!object_ownercheck(TypeRelationId, typeid, roleid))
2540 aclcheck_error_type(ACLCHECK_NOT_OWNER, typeid);
2542 break;
2543 case OBJECT_ROLE:
2546 * We treat roles as being "owned" by those with CREATEROLE priv,
2547 * except that superusers are only owned by superusers.
2549 if (superuser_arg(address.objectId))
2551 if (!superuser_arg(roleid))
2552 ereport(ERROR,
2553 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2554 errmsg("must be superuser")));
2556 else
2558 if (!has_createrole_privilege(roleid))
2559 ereport(ERROR,
2560 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2561 errmsg("must have CREATEROLE privilege")));
2563 break;
2564 case OBJECT_TSPARSER:
2565 case OBJECT_TSTEMPLATE:
2566 case OBJECT_ACCESS_METHOD:
2567 case OBJECT_PARAMETER_ACL:
2568 /* We treat these object types as being owned by superusers */
2569 if (!superuser_arg(roleid))
2570 ereport(ERROR,
2571 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2572 errmsg("must be superuser")));
2573 break;
2574 default:
2575 elog(ERROR, "unrecognized object type: %d",
2576 (int) objtype);
2581 * get_object_namespace
2583 * Find the schema containing the specified object. For non-schema objects,
2584 * this function returns InvalidOid.
2587 get_object_namespace(const ObjectAddress *address)
2589 int cache;
2590 HeapTuple tuple;
2591 bool isnull;
2592 Oid oid;
2593 const ObjectPropertyType *property;
2595 /* If not owned by a namespace, just return InvalidOid. */
2596 property = get_object_property_data(address->classId);
2597 if (property->attnum_namespace == InvalidAttrNumber)
2598 return InvalidOid;
2600 /* Currently, we can only handle object types with system caches. */
2601 cache = property->oid_catcache_id;
2602 Assert(cache != -1);
2604 /* Fetch tuple from syscache and extract namespace attribute. */
2605 tuple = SearchSysCache1(cache, ObjectIdGetDatum(address->objectId));
2606 if (!HeapTupleIsValid(tuple))
2607 elog(ERROR, "cache lookup failed for cache %d oid %u",
2608 cache, address->objectId);
2609 oid = DatumGetObjectId(SysCacheGetAttr(cache,
2610 tuple,
2611 property->attnum_namespace,
2612 &isnull));
2613 Assert(!isnull);
2614 ReleaseSysCache(tuple);
2616 return oid;
2620 * Return ObjectType for the given object type as given by
2621 * getObjectTypeDescription; if no valid ObjectType code exists, but it's a
2622 * possible output type from getObjectTypeDescription, return -1.
2623 * Otherwise, an error is thrown.
2626 read_objtype_from_string(const char *objtype)
2628 int i;
2630 for (i = 0; i < lengthof(ObjectTypeMap); i++)
2632 if (strcmp(ObjectTypeMap[i].tm_name, objtype) == 0)
2633 return ObjectTypeMap[i].tm_type;
2635 ereport(ERROR,
2636 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2637 errmsg("unrecognized object type \"%s\"", objtype)));
2639 return -1; /* keep compiler quiet */
2643 * Interfaces to reference fields of ObjectPropertyType
2645 const char *
2646 get_object_class_descr(Oid class_id)
2648 const ObjectPropertyType *prop = get_object_property_data(class_id);
2650 return prop->class_descr;
2654 get_object_oid_index(Oid class_id)
2656 const ObjectPropertyType *prop = get_object_property_data(class_id);
2658 return prop->oid_index_oid;
2662 get_object_catcache_oid(Oid class_id)
2664 const ObjectPropertyType *prop = get_object_property_data(class_id);
2666 return prop->oid_catcache_id;
2670 get_object_catcache_name(Oid class_id)
2672 const ObjectPropertyType *prop = get_object_property_data(class_id);
2674 return prop->name_catcache_id;
2677 AttrNumber
2678 get_object_attnum_oid(Oid class_id)
2680 const ObjectPropertyType *prop = get_object_property_data(class_id);
2682 return prop->attnum_oid;
2685 AttrNumber
2686 get_object_attnum_name(Oid class_id)
2688 const ObjectPropertyType *prop = get_object_property_data(class_id);
2690 return prop->attnum_name;
2693 AttrNumber
2694 get_object_attnum_namespace(Oid class_id)
2696 const ObjectPropertyType *prop = get_object_property_data(class_id);
2698 return prop->attnum_namespace;
2701 AttrNumber
2702 get_object_attnum_owner(Oid class_id)
2704 const ObjectPropertyType *prop = get_object_property_data(class_id);
2706 return prop->attnum_owner;
2709 AttrNumber
2710 get_object_attnum_acl(Oid class_id)
2712 const ObjectPropertyType *prop = get_object_property_data(class_id);
2714 return prop->attnum_acl;
2718 * get_object_type
2720 * Return the object type associated with a given object. This routine
2721 * is primarily used to determine the object type to mention in ACL check
2722 * error messages, so it's desirable for it to avoid failing.
2724 ObjectType
2725 get_object_type(Oid class_id, Oid object_id)
2727 const ObjectPropertyType *prop = get_object_property_data(class_id);
2729 if (prop->objtype == OBJECT_TABLE)
2732 * If the property data says it's a table, dig a little deeper to get
2733 * the real relation kind, so that callers can produce more precise
2734 * error messages.
2736 return get_relkind_objtype(get_rel_relkind(object_id));
2738 else
2739 return prop->objtype;
2742 bool
2743 get_object_namensp_unique(Oid class_id)
2745 const ObjectPropertyType *prop = get_object_property_data(class_id);
2747 return prop->is_nsp_name_unique;
2751 * Return whether we have useful data for the given object class in the
2752 * ObjectProperty table.
2754 bool
2755 is_objectclass_supported(Oid class_id)
2757 int index;
2759 for (index = 0; index < lengthof(ObjectProperty); index++)
2761 if (ObjectProperty[index].class_oid == class_id)
2762 return true;
2765 return false;
2769 * Find ObjectProperty structure by class_id.
2771 static const ObjectPropertyType *
2772 get_object_property_data(Oid class_id)
2774 static const ObjectPropertyType *prop_last = NULL;
2775 int index;
2778 * A shortcut to speed up multiple consecutive lookups of a particular
2779 * object class.
2781 if (prop_last && prop_last->class_oid == class_id)
2782 return prop_last;
2784 for (index = 0; index < lengthof(ObjectProperty); index++)
2786 if (ObjectProperty[index].class_oid == class_id)
2788 prop_last = &ObjectProperty[index];
2789 return &ObjectProperty[index];
2793 ereport(ERROR,
2794 (errmsg_internal("unrecognized class ID: %u", class_id)));
2796 return NULL; /* keep MSC compiler happy */
2800 * Return a copy of the tuple for the object with the given object OID, from
2801 * the given catalog (which must have been opened by the caller and suitably
2802 * locked). NULL is returned if the OID is not found.
2804 * We try a syscache first, if available.
2806 HeapTuple
2807 get_catalog_object_by_oid(Relation catalog, AttrNumber oidcol, Oid objectId)
2809 HeapTuple tuple;
2810 Oid classId = RelationGetRelid(catalog);
2811 int oidCacheId = get_object_catcache_oid(classId);
2813 if (oidCacheId > 0)
2815 tuple = SearchSysCacheCopy1(oidCacheId, ObjectIdGetDatum(objectId));
2816 if (!HeapTupleIsValid(tuple)) /* should not happen */
2817 return NULL;
2819 else
2821 Oid oidIndexId = get_object_oid_index(classId);
2822 SysScanDesc scan;
2823 ScanKeyData skey;
2825 Assert(OidIsValid(oidIndexId));
2827 ScanKeyInit(&skey,
2828 oidcol,
2829 BTEqualStrategyNumber, F_OIDEQ,
2830 ObjectIdGetDatum(objectId));
2832 scan = systable_beginscan(catalog, oidIndexId, true,
2833 NULL, 1, &skey);
2834 tuple = systable_getnext(scan);
2835 if (!HeapTupleIsValid(tuple))
2837 systable_endscan(scan);
2838 return NULL;
2840 tuple = heap_copytuple(tuple);
2842 systable_endscan(scan);
2845 return tuple;
2849 * getPublicationSchemaInfo
2851 * Get publication name and schema name from the object address into pubname and
2852 * nspname. Both pubname and nspname are palloc'd strings which will be freed by
2853 * the caller.
2855 static bool
2856 getPublicationSchemaInfo(const ObjectAddress *object, bool missing_ok,
2857 char **pubname, char **nspname)
2859 HeapTuple tup;
2860 Form_pg_publication_namespace pnform;
2862 tup = SearchSysCache1(PUBLICATIONNAMESPACE,
2863 ObjectIdGetDatum(object->objectId));
2864 if (!HeapTupleIsValid(tup))
2866 if (!missing_ok)
2867 elog(ERROR, "cache lookup failed for publication schema %u",
2868 object->objectId);
2869 return false;
2872 pnform = (Form_pg_publication_namespace) GETSTRUCT(tup);
2873 *pubname = get_publication_name(pnform->pnpubid, missing_ok);
2874 if (!(*pubname))
2876 ReleaseSysCache(tup);
2877 return false;
2880 *nspname = get_namespace_name(pnform->pnnspid);
2881 if (!(*nspname))
2883 Oid schemaid = pnform->pnnspid;
2885 pfree(*pubname);
2886 ReleaseSysCache(tup);
2887 if (!missing_ok)
2888 elog(ERROR, "cache lookup failed for schema %u",
2889 schemaid);
2890 return false;
2893 ReleaseSysCache(tup);
2894 return true;
2898 * getObjectDescription: build an object description for messages
2900 * The result is a palloc'd string. NULL is returned for an undefined
2901 * object if missing_ok is true, else an error is generated.
2903 char *
2904 getObjectDescription(const ObjectAddress *object, bool missing_ok)
2906 StringInfoData buffer;
2908 initStringInfo(&buffer);
2910 switch (getObjectClass(object))
2912 case OCLASS_CLASS:
2913 if (object->objectSubId == 0)
2914 getRelationDescription(&buffer, object->objectId, missing_ok);
2915 else
2917 /* column, not whole relation */
2918 StringInfoData rel;
2919 char *attname = get_attname(object->objectId,
2920 object->objectSubId,
2921 missing_ok);
2923 if (!attname)
2924 break;
2926 initStringInfo(&rel);
2927 getRelationDescription(&rel, object->objectId, missing_ok);
2928 /* translator: second %s is, e.g., "table %s" */
2929 appendStringInfo(&buffer, _("column %s of %s"),
2930 attname, rel.data);
2931 pfree(rel.data);
2933 break;
2935 case OCLASS_PROC:
2937 bits16 flags = FORMAT_PROC_INVALID_AS_NULL;
2938 char *proname = format_procedure_extended(object->objectId,
2939 flags);
2941 if (proname == NULL)
2942 break;
2944 appendStringInfo(&buffer, _("function %s"), proname);
2945 break;
2948 case OCLASS_TYPE:
2950 bits16 flags = FORMAT_TYPE_INVALID_AS_NULL;
2951 char *typname = format_type_extended(object->objectId, -1,
2952 flags);
2954 if (typname == NULL)
2955 break;
2957 appendStringInfo(&buffer, _("type %s"), typname);
2958 break;
2961 case OCLASS_CAST:
2963 Relation castDesc;
2964 ScanKeyData skey[1];
2965 SysScanDesc rcscan;
2966 HeapTuple tup;
2967 Form_pg_cast castForm;
2969 castDesc = table_open(CastRelationId, AccessShareLock);
2971 ScanKeyInit(&skey[0],
2972 Anum_pg_cast_oid,
2973 BTEqualStrategyNumber, F_OIDEQ,
2974 ObjectIdGetDatum(object->objectId));
2976 rcscan = systable_beginscan(castDesc, CastOidIndexId, true,
2977 NULL, 1, skey);
2979 tup = systable_getnext(rcscan);
2981 if (!HeapTupleIsValid(tup))
2983 if (!missing_ok)
2984 elog(ERROR, "could not find tuple for cast %u",
2985 object->objectId);
2987 systable_endscan(rcscan);
2988 table_close(castDesc, AccessShareLock);
2989 break;
2992 castForm = (Form_pg_cast) GETSTRUCT(tup);
2994 appendStringInfo(&buffer, _("cast from %s to %s"),
2995 format_type_be(castForm->castsource),
2996 format_type_be(castForm->casttarget));
2998 systable_endscan(rcscan);
2999 table_close(castDesc, AccessShareLock);
3000 break;
3003 case OCLASS_COLLATION:
3005 HeapTuple collTup;
3006 Form_pg_collation coll;
3007 char *nspname;
3009 collTup = SearchSysCache1(COLLOID,
3010 ObjectIdGetDatum(object->objectId));
3011 if (!HeapTupleIsValid(collTup))
3013 if (!missing_ok)
3014 elog(ERROR, "cache lookup failed for collation %u",
3015 object->objectId);
3016 break;
3019 coll = (Form_pg_collation) GETSTRUCT(collTup);
3021 /* Qualify the name if not visible in search path */
3022 if (CollationIsVisible(object->objectId))
3023 nspname = NULL;
3024 else
3025 nspname = get_namespace_name(coll->collnamespace);
3027 appendStringInfo(&buffer, _("collation %s"),
3028 quote_qualified_identifier(nspname,
3029 NameStr(coll->collname)));
3030 ReleaseSysCache(collTup);
3031 break;
3034 case OCLASS_CONSTRAINT:
3036 HeapTuple conTup;
3037 Form_pg_constraint con;
3039 conTup = SearchSysCache1(CONSTROID,
3040 ObjectIdGetDatum(object->objectId));
3041 if (!HeapTupleIsValid(conTup))
3043 if (!missing_ok)
3044 elog(ERROR, "cache lookup failed for constraint %u",
3045 object->objectId);
3046 break;
3049 con = (Form_pg_constraint) GETSTRUCT(conTup);
3051 if (OidIsValid(con->conrelid))
3053 StringInfoData rel;
3055 initStringInfo(&rel);
3056 getRelationDescription(&rel, con->conrelid, false);
3057 /* translator: second %s is, e.g., "table %s" */
3058 appendStringInfo(&buffer, _("constraint %s on %s"),
3059 NameStr(con->conname), rel.data);
3060 pfree(rel.data);
3062 else
3064 appendStringInfo(&buffer, _("constraint %s"),
3065 NameStr(con->conname));
3068 ReleaseSysCache(conTup);
3069 break;
3072 case OCLASS_CONVERSION:
3074 HeapTuple conTup;
3075 Form_pg_conversion conv;
3076 char *nspname;
3078 conTup = SearchSysCache1(CONVOID,
3079 ObjectIdGetDatum(object->objectId));
3080 if (!HeapTupleIsValid(conTup))
3082 if (!missing_ok)
3083 elog(ERROR, "cache lookup failed for conversion %u",
3084 object->objectId);
3085 break;
3088 conv = (Form_pg_conversion) GETSTRUCT(conTup);
3090 /* Qualify the name if not visible in search path */
3091 if (ConversionIsVisible(object->objectId))
3092 nspname = NULL;
3093 else
3094 nspname = get_namespace_name(conv->connamespace);
3096 appendStringInfo(&buffer, _("conversion %s"),
3097 quote_qualified_identifier(nspname,
3098 NameStr(conv->conname)));
3099 ReleaseSysCache(conTup);
3100 break;
3103 case OCLASS_DEFAULT:
3105 ObjectAddress colobject;
3107 colobject = GetAttrDefaultColumnAddress(object->objectId);
3109 if (!OidIsValid(colobject.objectId))
3111 if (!missing_ok)
3112 elog(ERROR, "could not find tuple for attrdef %u",
3113 object->objectId);
3114 break;
3117 /* translator: %s is typically "column %s of table %s" */
3118 appendStringInfo(&buffer, _("default value for %s"),
3119 getObjectDescription(&colobject, false));
3120 break;
3123 case OCLASS_LANGUAGE:
3125 char *langname = get_language_name(object->objectId,
3126 missing_ok);
3128 if (langname)
3129 appendStringInfo(&buffer, _("language %s"),
3130 get_language_name(object->objectId, false));
3131 break;
3134 case OCLASS_LARGEOBJECT:
3135 if (!LargeObjectExists(object->objectId))
3136 break;
3137 appendStringInfo(&buffer, _("large object %u"),
3138 object->objectId);
3139 break;
3141 case OCLASS_OPERATOR:
3143 bits16 flags = FORMAT_OPERATOR_INVALID_AS_NULL;
3144 char *oprname = format_operator_extended(object->objectId,
3145 flags);
3147 if (oprname == NULL)
3148 break;
3150 appendStringInfo(&buffer, _("operator %s"), oprname);
3151 break;
3154 case OCLASS_OPCLASS:
3156 HeapTuple opcTup;
3157 Form_pg_opclass opcForm;
3158 HeapTuple amTup;
3159 Form_pg_am amForm;
3160 char *nspname;
3162 opcTup = SearchSysCache1(CLAOID,
3163 ObjectIdGetDatum(object->objectId));
3164 if (!HeapTupleIsValid(opcTup))
3166 if (!missing_ok)
3167 elog(ERROR, "cache lookup failed for opclass %u",
3168 object->objectId);
3169 break;
3172 opcForm = (Form_pg_opclass) GETSTRUCT(opcTup);
3174 amTup = SearchSysCache1(AMOID,
3175 ObjectIdGetDatum(opcForm->opcmethod));
3176 if (!HeapTupleIsValid(amTup))
3177 elog(ERROR, "cache lookup failed for access method %u",
3178 opcForm->opcmethod);
3179 amForm = (Form_pg_am) GETSTRUCT(amTup);
3181 /* Qualify the name if not visible in search path */
3182 if (OpclassIsVisible(object->objectId))
3183 nspname = NULL;
3184 else
3185 nspname = get_namespace_name(opcForm->opcnamespace);
3187 appendStringInfo(&buffer, _("operator class %s for access method %s"),
3188 quote_qualified_identifier(nspname,
3189 NameStr(opcForm->opcname)),
3190 NameStr(amForm->amname));
3192 ReleaseSysCache(amTup);
3193 ReleaseSysCache(opcTup);
3194 break;
3197 case OCLASS_OPFAMILY:
3198 getOpFamilyDescription(&buffer, object->objectId, missing_ok);
3199 break;
3201 case OCLASS_AM:
3203 HeapTuple tup;
3205 tup = SearchSysCache1(AMOID,
3206 ObjectIdGetDatum(object->objectId));
3207 if (!HeapTupleIsValid(tup))
3209 if (!missing_ok)
3210 elog(ERROR, "cache lookup failed for access method %u",
3211 object->objectId);
3212 break;
3215 appendStringInfo(&buffer, _("access method %s"),
3216 NameStr(((Form_pg_am) GETSTRUCT(tup))->amname));
3217 ReleaseSysCache(tup);
3218 break;
3221 case OCLASS_AMOP:
3223 Relation amopDesc;
3224 HeapTuple tup;
3225 ScanKeyData skey[1];
3226 SysScanDesc amscan;
3227 Form_pg_amop amopForm;
3228 StringInfoData opfam;
3230 amopDesc = table_open(AccessMethodOperatorRelationId,
3231 AccessShareLock);
3233 ScanKeyInit(&skey[0],
3234 Anum_pg_amop_oid,
3235 BTEqualStrategyNumber, F_OIDEQ,
3236 ObjectIdGetDatum(object->objectId));
3238 amscan = systable_beginscan(amopDesc, AccessMethodOperatorOidIndexId, true,
3239 NULL, 1, skey);
3241 tup = systable_getnext(amscan);
3243 if (!HeapTupleIsValid(tup))
3245 if (!missing_ok)
3246 elog(ERROR, "could not find tuple for amop entry %u",
3247 object->objectId);
3249 systable_endscan(amscan);
3250 table_close(amopDesc, AccessShareLock);
3251 break;
3254 amopForm = (Form_pg_amop) GETSTRUCT(tup);
3256 initStringInfo(&opfam);
3257 getOpFamilyDescription(&opfam, amopForm->amopfamily, false);
3259 /*------
3260 translator: %d is the operator strategy (a number), the
3261 first two %s's are data type names, the third %s is the
3262 description of the operator family, and the last %s is the
3263 textual form of the operator with arguments. */
3264 appendStringInfo(&buffer, _("operator %d (%s, %s) of %s: %s"),
3265 amopForm->amopstrategy,
3266 format_type_be(amopForm->amoplefttype),
3267 format_type_be(amopForm->amoprighttype),
3268 opfam.data,
3269 format_operator(amopForm->amopopr));
3271 pfree(opfam.data);
3273 systable_endscan(amscan);
3274 table_close(amopDesc, AccessShareLock);
3275 break;
3278 case OCLASS_AMPROC:
3280 Relation amprocDesc;
3281 ScanKeyData skey[1];
3282 SysScanDesc amscan;
3283 HeapTuple tup;
3284 Form_pg_amproc amprocForm;
3285 StringInfoData opfam;
3287 amprocDesc = table_open(AccessMethodProcedureRelationId,
3288 AccessShareLock);
3290 ScanKeyInit(&skey[0],
3291 Anum_pg_amproc_oid,
3292 BTEqualStrategyNumber, F_OIDEQ,
3293 ObjectIdGetDatum(object->objectId));
3295 amscan = systable_beginscan(amprocDesc, AccessMethodProcedureOidIndexId, true,
3296 NULL, 1, skey);
3298 tup = systable_getnext(amscan);
3300 if (!HeapTupleIsValid(tup))
3302 if (!missing_ok)
3303 elog(ERROR, "could not find tuple for amproc entry %u",
3304 object->objectId);
3306 systable_endscan(amscan);
3307 table_close(amprocDesc, AccessShareLock);
3308 break;
3311 amprocForm = (Form_pg_amproc) GETSTRUCT(tup);
3313 initStringInfo(&opfam);
3314 getOpFamilyDescription(&opfam, amprocForm->amprocfamily, false);
3316 /*------
3317 translator: %d is the function number, the first two %s's
3318 are data type names, the third %s is the description of the
3319 operator family, and the last %s is the textual form of the
3320 function with arguments. */
3321 appendStringInfo(&buffer, _("function %d (%s, %s) of %s: %s"),
3322 amprocForm->amprocnum,
3323 format_type_be(amprocForm->amproclefttype),
3324 format_type_be(amprocForm->amprocrighttype),
3325 opfam.data,
3326 format_procedure(amprocForm->amproc));
3328 pfree(opfam.data);
3330 systable_endscan(amscan);
3331 table_close(amprocDesc, AccessShareLock);
3332 break;
3335 case OCLASS_REWRITE:
3337 Relation ruleDesc;
3338 ScanKeyData skey[1];
3339 SysScanDesc rcscan;
3340 HeapTuple tup;
3341 Form_pg_rewrite rule;
3342 StringInfoData rel;
3344 ruleDesc = table_open(RewriteRelationId, AccessShareLock);
3346 ScanKeyInit(&skey[0],
3347 Anum_pg_rewrite_oid,
3348 BTEqualStrategyNumber, F_OIDEQ,
3349 ObjectIdGetDatum(object->objectId));
3351 rcscan = systable_beginscan(ruleDesc, RewriteOidIndexId, true,
3352 NULL, 1, skey);
3354 tup = systable_getnext(rcscan);
3356 if (!HeapTupleIsValid(tup))
3358 if (!missing_ok)
3359 elog(ERROR, "could not find tuple for rule %u",
3360 object->objectId);
3362 systable_endscan(rcscan);
3363 table_close(ruleDesc, AccessShareLock);
3364 break;
3367 rule = (Form_pg_rewrite) GETSTRUCT(tup);
3369 initStringInfo(&rel);
3370 getRelationDescription(&rel, rule->ev_class, false);
3372 /* translator: second %s is, e.g., "table %s" */
3373 appendStringInfo(&buffer, _("rule %s on %s"),
3374 NameStr(rule->rulename), rel.data);
3375 pfree(rel.data);
3376 systable_endscan(rcscan);
3377 table_close(ruleDesc, AccessShareLock);
3378 break;
3381 case OCLASS_TRIGGER:
3383 Relation trigDesc;
3384 ScanKeyData skey[1];
3385 SysScanDesc tgscan;
3386 HeapTuple tup;
3387 Form_pg_trigger trig;
3388 StringInfoData rel;
3390 trigDesc = table_open(TriggerRelationId, AccessShareLock);
3392 ScanKeyInit(&skey[0],
3393 Anum_pg_trigger_oid,
3394 BTEqualStrategyNumber, F_OIDEQ,
3395 ObjectIdGetDatum(object->objectId));
3397 tgscan = systable_beginscan(trigDesc, TriggerOidIndexId, true,
3398 NULL, 1, skey);
3400 tup = systable_getnext(tgscan);
3402 if (!HeapTupleIsValid(tup))
3404 if (!missing_ok)
3405 elog(ERROR, "could not find tuple for trigger %u",
3406 object->objectId);
3408 systable_endscan(tgscan);
3409 table_close(trigDesc, AccessShareLock);
3410 break;
3413 trig = (Form_pg_trigger) GETSTRUCT(tup);
3415 initStringInfo(&rel);
3416 getRelationDescription(&rel, trig->tgrelid, false);
3418 /* translator: second %s is, e.g., "table %s" */
3419 appendStringInfo(&buffer, _("trigger %s on %s"),
3420 NameStr(trig->tgname), rel.data);
3421 pfree(rel.data);
3422 systable_endscan(tgscan);
3423 table_close(trigDesc, AccessShareLock);
3424 break;
3427 case OCLASS_SCHEMA:
3429 char *nspname;
3431 nspname = get_namespace_name(object->objectId);
3432 if (!nspname)
3434 if (!missing_ok)
3435 elog(ERROR, "cache lookup failed for namespace %u",
3436 object->objectId);
3437 break;
3439 appendStringInfo(&buffer, _("schema %s"), nspname);
3440 break;
3443 case OCLASS_STATISTIC_EXT:
3445 HeapTuple stxTup;
3446 Form_pg_statistic_ext stxForm;
3447 char *nspname;
3449 stxTup = SearchSysCache1(STATEXTOID,
3450 ObjectIdGetDatum(object->objectId));
3451 if (!HeapTupleIsValid(stxTup))
3453 if (!missing_ok)
3454 elog(ERROR, "could not find tuple for statistics object %u",
3455 object->objectId);
3456 break;
3459 stxForm = (Form_pg_statistic_ext) GETSTRUCT(stxTup);
3461 /* Qualify the name if not visible in search path */
3462 if (StatisticsObjIsVisible(object->objectId))
3463 nspname = NULL;
3464 else
3465 nspname = get_namespace_name(stxForm->stxnamespace);
3467 appendStringInfo(&buffer, _("statistics object %s"),
3468 quote_qualified_identifier(nspname,
3469 NameStr(stxForm->stxname)));
3471 ReleaseSysCache(stxTup);
3472 break;
3475 case OCLASS_TSPARSER:
3477 HeapTuple tup;
3478 Form_pg_ts_parser prsForm;
3479 char *nspname;
3481 tup = SearchSysCache1(TSPARSEROID,
3482 ObjectIdGetDatum(object->objectId));
3483 if (!HeapTupleIsValid(tup))
3485 if (!missing_ok)
3486 elog(ERROR, "cache lookup failed for text search parser %u",
3487 object->objectId);
3488 break;
3490 prsForm = (Form_pg_ts_parser) GETSTRUCT(tup);
3492 /* Qualify the name if not visible in search path */
3493 if (TSParserIsVisible(object->objectId))
3494 nspname = NULL;
3495 else
3496 nspname = get_namespace_name(prsForm->prsnamespace);
3498 appendStringInfo(&buffer, _("text search parser %s"),
3499 quote_qualified_identifier(nspname,
3500 NameStr(prsForm->prsname)));
3501 ReleaseSysCache(tup);
3502 break;
3505 case OCLASS_TSDICT:
3507 HeapTuple tup;
3508 Form_pg_ts_dict dictForm;
3509 char *nspname;
3511 tup = SearchSysCache1(TSDICTOID,
3512 ObjectIdGetDatum(object->objectId));
3513 if (!HeapTupleIsValid(tup))
3515 if (!missing_ok)
3516 elog(ERROR, "cache lookup failed for text search dictionary %u",
3517 object->objectId);
3518 break;
3521 dictForm = (Form_pg_ts_dict) GETSTRUCT(tup);
3523 /* Qualify the name if not visible in search path */
3524 if (TSDictionaryIsVisible(object->objectId))
3525 nspname = NULL;
3526 else
3527 nspname = get_namespace_name(dictForm->dictnamespace);
3529 appendStringInfo(&buffer, _("text search dictionary %s"),
3530 quote_qualified_identifier(nspname,
3531 NameStr(dictForm->dictname)));
3532 ReleaseSysCache(tup);
3533 break;
3536 case OCLASS_TSTEMPLATE:
3538 HeapTuple tup;
3539 Form_pg_ts_template tmplForm;
3540 char *nspname;
3542 tup = SearchSysCache1(TSTEMPLATEOID,
3543 ObjectIdGetDatum(object->objectId));
3544 if (!HeapTupleIsValid(tup))
3546 if (!missing_ok)
3547 elog(ERROR, "cache lookup failed for text search template %u",
3548 object->objectId);
3549 break;
3552 tmplForm = (Form_pg_ts_template) GETSTRUCT(tup);
3554 /* Qualify the name if not visible in search path */
3555 if (TSTemplateIsVisible(object->objectId))
3556 nspname = NULL;
3557 else
3558 nspname = get_namespace_name(tmplForm->tmplnamespace);
3560 appendStringInfo(&buffer, _("text search template %s"),
3561 quote_qualified_identifier(nspname,
3562 NameStr(tmplForm->tmplname)));
3563 ReleaseSysCache(tup);
3564 break;
3567 case OCLASS_TSCONFIG:
3569 HeapTuple tup;
3570 Form_pg_ts_config cfgForm;
3571 char *nspname;
3573 tup = SearchSysCache1(TSCONFIGOID,
3574 ObjectIdGetDatum(object->objectId));
3575 if (!HeapTupleIsValid(tup))
3577 if (!missing_ok)
3578 elog(ERROR, "cache lookup failed for text search configuration %u",
3579 object->objectId);
3580 break;
3583 cfgForm = (Form_pg_ts_config) GETSTRUCT(tup);
3585 /* Qualify the name if not visible in search path */
3586 if (TSConfigIsVisible(object->objectId))
3587 nspname = NULL;
3588 else
3589 nspname = get_namespace_name(cfgForm->cfgnamespace);
3591 appendStringInfo(&buffer, _("text search configuration %s"),
3592 quote_qualified_identifier(nspname,
3593 NameStr(cfgForm->cfgname)));
3594 ReleaseSysCache(tup);
3595 break;
3598 case OCLASS_ROLE:
3600 char *username = GetUserNameFromId(object->objectId,
3601 missing_ok);
3603 if (username)
3604 appendStringInfo(&buffer, _("role %s"), username);
3605 break;
3608 case OCLASS_ROLE_MEMBERSHIP:
3610 Relation amDesc;
3611 ScanKeyData skey[1];
3612 SysScanDesc rcscan;
3613 HeapTuple tup;
3614 Form_pg_auth_members amForm;
3616 amDesc = table_open(AuthMemRelationId, AccessShareLock);
3618 ScanKeyInit(&skey[0],
3619 Anum_pg_auth_members_oid,
3620 BTEqualStrategyNumber, F_OIDEQ,
3621 ObjectIdGetDatum(object->objectId));
3623 rcscan = systable_beginscan(amDesc, AuthMemOidIndexId, true,
3624 NULL, 1, skey);
3626 tup = systable_getnext(rcscan);
3628 if (!HeapTupleIsValid(tup))
3630 if (!missing_ok)
3631 elog(ERROR, "could not find tuple for role membership %u",
3632 object->objectId);
3634 systable_endscan(rcscan);
3635 table_close(amDesc, AccessShareLock);
3636 break;
3639 amForm = (Form_pg_auth_members) GETSTRUCT(tup);
3641 appendStringInfo(&buffer, _("membership of role %s in role %s"),
3642 GetUserNameFromId(amForm->member, false),
3643 GetUserNameFromId(amForm->roleid, false));
3645 systable_endscan(rcscan);
3646 table_close(amDesc, AccessShareLock);
3647 break;
3650 case OCLASS_DATABASE:
3652 char *datname;
3654 datname = get_database_name(object->objectId);
3655 if (!datname)
3657 if (!missing_ok)
3658 elog(ERROR, "cache lookup failed for database %u",
3659 object->objectId);
3660 break;
3662 appendStringInfo(&buffer, _("database %s"), datname);
3663 break;
3666 case OCLASS_TBLSPACE:
3668 char *tblspace;
3670 tblspace = get_tablespace_name(object->objectId);
3671 if (!tblspace)
3673 if (!missing_ok)
3674 elog(ERROR, "cache lookup failed for tablespace %u",
3675 object->objectId);
3676 break;
3678 appendStringInfo(&buffer, _("tablespace %s"), tblspace);
3679 break;
3682 case OCLASS_FDW:
3684 ForeignDataWrapper *fdw;
3686 fdw = GetForeignDataWrapperExtended(object->objectId,
3687 missing_ok);
3688 if (fdw)
3689 appendStringInfo(&buffer, _("foreign-data wrapper %s"), fdw->fdwname);
3690 break;
3693 case OCLASS_FOREIGN_SERVER:
3695 ForeignServer *srv;
3697 srv = GetForeignServerExtended(object->objectId, missing_ok);
3698 if (srv)
3699 appendStringInfo(&buffer, _("server %s"), srv->servername);
3700 break;
3703 case OCLASS_USER_MAPPING:
3705 HeapTuple tup;
3706 Oid useid;
3707 char *usename;
3708 Form_pg_user_mapping umform;
3709 ForeignServer *srv;
3711 tup = SearchSysCache1(USERMAPPINGOID,
3712 ObjectIdGetDatum(object->objectId));
3713 if (!HeapTupleIsValid(tup))
3715 if (!missing_ok)
3716 elog(ERROR, "cache lookup failed for user mapping %u",
3717 object->objectId);
3718 break;
3721 umform = (Form_pg_user_mapping) GETSTRUCT(tup);
3722 useid = umform->umuser;
3723 srv = GetForeignServer(umform->umserver);
3725 ReleaseSysCache(tup);
3727 if (OidIsValid(useid))
3728 usename = GetUserNameFromId(useid, false);
3729 else
3730 usename = "public";
3732 appendStringInfo(&buffer, _("user mapping for %s on server %s"), usename,
3733 srv->servername);
3734 break;
3737 case OCLASS_DEFACL:
3739 Relation defaclrel;
3740 ScanKeyData skey[1];
3741 SysScanDesc rcscan;
3742 HeapTuple tup;
3743 Form_pg_default_acl defacl;
3744 char *rolename;
3745 char *nspname;
3747 defaclrel = table_open(DefaultAclRelationId, AccessShareLock);
3749 ScanKeyInit(&skey[0],
3750 Anum_pg_default_acl_oid,
3751 BTEqualStrategyNumber, F_OIDEQ,
3752 ObjectIdGetDatum(object->objectId));
3754 rcscan = systable_beginscan(defaclrel, DefaultAclOidIndexId,
3755 true, NULL, 1, skey);
3757 tup = systable_getnext(rcscan);
3759 if (!HeapTupleIsValid(tup))
3761 if (!missing_ok)
3762 elog(ERROR, "could not find tuple for default ACL %u",
3763 object->objectId);
3765 systable_endscan(rcscan);
3766 table_close(defaclrel, AccessShareLock);
3767 break;
3770 defacl = (Form_pg_default_acl) GETSTRUCT(tup);
3772 rolename = GetUserNameFromId(defacl->defaclrole, false);
3774 if (OidIsValid(defacl->defaclnamespace))
3775 nspname = get_namespace_name(defacl->defaclnamespace);
3776 else
3777 nspname = NULL;
3779 switch (defacl->defaclobjtype)
3781 case DEFACLOBJ_RELATION:
3782 if (nspname)
3783 appendStringInfo(&buffer,
3784 _("default privileges on new relations belonging to role %s in schema %s"),
3785 rolename, nspname);
3786 else
3787 appendStringInfo(&buffer,
3788 _("default privileges on new relations belonging to role %s"),
3789 rolename);
3790 break;
3791 case DEFACLOBJ_SEQUENCE:
3792 if (nspname)
3793 appendStringInfo(&buffer,
3794 _("default privileges on new sequences belonging to role %s in schema %s"),
3795 rolename, nspname);
3796 else
3797 appendStringInfo(&buffer,
3798 _("default privileges on new sequences belonging to role %s"),
3799 rolename);
3800 break;
3801 case DEFACLOBJ_FUNCTION:
3802 if (nspname)
3803 appendStringInfo(&buffer,
3804 _("default privileges on new functions belonging to role %s in schema %s"),
3805 rolename, nspname);
3806 else
3807 appendStringInfo(&buffer,
3808 _("default privileges on new functions belonging to role %s"),
3809 rolename);
3810 break;
3811 case DEFACLOBJ_TYPE:
3812 if (nspname)
3813 appendStringInfo(&buffer,
3814 _("default privileges on new types belonging to role %s in schema %s"),
3815 rolename, nspname);
3816 else
3817 appendStringInfo(&buffer,
3818 _("default privileges on new types belonging to role %s"),
3819 rolename);
3820 break;
3821 case DEFACLOBJ_NAMESPACE:
3822 Assert(!nspname);
3823 appendStringInfo(&buffer,
3824 _("default privileges on new schemas belonging to role %s"),
3825 rolename);
3826 break;
3827 default:
3828 /* shouldn't get here */
3829 if (nspname)
3830 appendStringInfo(&buffer,
3831 _("default privileges belonging to role %s in schema %s"),
3832 rolename, nspname);
3833 else
3834 appendStringInfo(&buffer,
3835 _("default privileges belonging to role %s"),
3836 rolename);
3837 break;
3840 systable_endscan(rcscan);
3841 table_close(defaclrel, AccessShareLock);
3842 break;
3845 case OCLASS_EXTENSION:
3847 char *extname;
3849 extname = get_extension_name(object->objectId);
3850 if (!extname)
3852 if (!missing_ok)
3853 elog(ERROR, "cache lookup failed for extension %u",
3854 object->objectId);
3855 break;
3857 appendStringInfo(&buffer, _("extension %s"), extname);
3858 break;
3861 case OCLASS_EVENT_TRIGGER:
3863 HeapTuple tup;
3865 tup = SearchSysCache1(EVENTTRIGGEROID,
3866 ObjectIdGetDatum(object->objectId));
3867 if (!HeapTupleIsValid(tup))
3869 if (!missing_ok)
3870 elog(ERROR, "cache lookup failed for event trigger %u",
3871 object->objectId);
3872 break;
3874 appendStringInfo(&buffer, _("event trigger %s"),
3875 NameStr(((Form_pg_event_trigger) GETSTRUCT(tup))->evtname));
3876 ReleaseSysCache(tup);
3877 break;
3880 case OCLASS_PARAMETER_ACL:
3882 HeapTuple tup;
3883 Datum nameDatum;
3884 bool isNull;
3885 char *parname;
3887 tup = SearchSysCache1(PARAMETERACLOID,
3888 ObjectIdGetDatum(object->objectId));
3889 if (!HeapTupleIsValid(tup))
3891 if (!missing_ok)
3892 elog(ERROR, "cache lookup failed for parameter ACL %u",
3893 object->objectId);
3894 break;
3896 nameDatum = SysCacheGetAttr(PARAMETERACLOID, tup,
3897 Anum_pg_parameter_acl_parname,
3898 &isNull);
3899 Assert(!isNull);
3900 parname = TextDatumGetCString(nameDatum);
3901 appendStringInfo(&buffer, _("parameter %s"), parname);
3902 ReleaseSysCache(tup);
3903 break;
3906 case OCLASS_POLICY:
3908 Relation policy_rel;
3909 ScanKeyData skey[1];
3910 SysScanDesc sscan;
3911 HeapTuple tuple;
3912 Form_pg_policy form_policy;
3913 StringInfoData rel;
3915 policy_rel = table_open(PolicyRelationId, AccessShareLock);
3917 ScanKeyInit(&skey[0],
3918 Anum_pg_policy_oid,
3919 BTEqualStrategyNumber, F_OIDEQ,
3920 ObjectIdGetDatum(object->objectId));
3922 sscan = systable_beginscan(policy_rel, PolicyOidIndexId,
3923 true, NULL, 1, skey);
3925 tuple = systable_getnext(sscan);
3927 if (!HeapTupleIsValid(tuple))
3929 if (!missing_ok)
3930 elog(ERROR, "could not find tuple for policy %u",
3931 object->objectId);
3933 systable_endscan(sscan);
3934 table_close(policy_rel, AccessShareLock);
3935 break;
3938 form_policy = (Form_pg_policy) GETSTRUCT(tuple);
3940 initStringInfo(&rel);
3941 getRelationDescription(&rel, form_policy->polrelid, false);
3943 /* translator: second %s is, e.g., "table %s" */
3944 appendStringInfo(&buffer, _("policy %s on %s"),
3945 NameStr(form_policy->polname), rel.data);
3946 pfree(rel.data);
3947 systable_endscan(sscan);
3948 table_close(policy_rel, AccessShareLock);
3949 break;
3952 case OCLASS_PUBLICATION:
3954 char *pubname = get_publication_name(object->objectId,
3955 missing_ok);
3957 if (pubname)
3958 appendStringInfo(&buffer, _("publication %s"), pubname);
3959 break;
3962 case OCLASS_PUBLICATION_NAMESPACE:
3964 char *pubname;
3965 char *nspname;
3967 if (!getPublicationSchemaInfo(object, missing_ok,
3968 &pubname, &nspname))
3969 break;
3971 appendStringInfo(&buffer, _("publication of schema %s in publication %s"),
3972 nspname, pubname);
3973 pfree(pubname);
3974 pfree(nspname);
3975 break;
3978 case OCLASS_PUBLICATION_REL:
3980 HeapTuple tup;
3981 char *pubname;
3982 Form_pg_publication_rel prform;
3983 StringInfoData rel;
3985 tup = SearchSysCache1(PUBLICATIONREL,
3986 ObjectIdGetDatum(object->objectId));
3987 if (!HeapTupleIsValid(tup))
3989 if (!missing_ok)
3990 elog(ERROR, "cache lookup failed for publication table %u",
3991 object->objectId);
3992 break;
3995 prform = (Form_pg_publication_rel) GETSTRUCT(tup);
3996 pubname = get_publication_name(prform->prpubid, false);
3998 initStringInfo(&rel);
3999 getRelationDescription(&rel, prform->prrelid, false);
4001 /* translator: first %s is, e.g., "table %s" */
4002 appendStringInfo(&buffer, _("publication of %s in publication %s"),
4003 rel.data, pubname);
4004 pfree(rel.data);
4005 ReleaseSysCache(tup);
4006 break;
4009 case OCLASS_SUBSCRIPTION:
4011 char *subname = get_subscription_name(object->objectId,
4012 missing_ok);
4014 if (subname)
4015 appendStringInfo(&buffer, _("subscription %s"), subname);
4016 break;
4019 case OCLASS_TRANSFORM:
4021 HeapTuple trfTup;
4022 Form_pg_transform trfForm;
4024 trfTup = SearchSysCache1(TRFOID,
4025 ObjectIdGetDatum(object->objectId));
4026 if (!HeapTupleIsValid(trfTup))
4028 if (!missing_ok)
4029 elog(ERROR, "could not find tuple for transform %u",
4030 object->objectId);
4031 break;
4034 trfForm = (Form_pg_transform) GETSTRUCT(trfTup);
4036 appendStringInfo(&buffer, _("transform for %s language %s"),
4037 format_type_be(trfForm->trftype),
4038 get_language_name(trfForm->trflang, false));
4040 ReleaseSysCache(trfTup);
4041 break;
4045 * There's intentionally no default: case here; we want the
4046 * compiler to warn if a new OCLASS hasn't been handled above.
4050 /* an empty buffer is equivalent to no object found */
4051 if (buffer.len == 0)
4052 return NULL;
4054 return buffer.data;
4058 * getObjectDescriptionOids: as above, except the object is specified by Oids
4060 char *
4061 getObjectDescriptionOids(Oid classid, Oid objid)
4063 ObjectAddress address;
4065 address.classId = classid;
4066 address.objectId = objid;
4067 address.objectSubId = 0;
4069 return getObjectDescription(&address, false);
4073 * subroutine for getObjectDescription: describe a relation
4075 * The result is appended to "buffer".
4077 static void
4078 getRelationDescription(StringInfo buffer, Oid relid, bool missing_ok)
4080 HeapTuple relTup;
4081 Form_pg_class relForm;
4082 char *nspname;
4083 char *relname;
4085 relTup = SearchSysCache1(RELOID,
4086 ObjectIdGetDatum(relid));
4087 if (!HeapTupleIsValid(relTup))
4089 if (!missing_ok)
4090 elog(ERROR, "cache lookup failed for relation %u", relid);
4091 return;
4093 relForm = (Form_pg_class) GETSTRUCT(relTup);
4095 /* Qualify the name if not visible in search path */
4096 if (RelationIsVisible(relid))
4097 nspname = NULL;
4098 else
4099 nspname = get_namespace_name(relForm->relnamespace);
4101 relname = quote_qualified_identifier(nspname, NameStr(relForm->relname));
4103 switch (relForm->relkind)
4105 case RELKIND_RELATION:
4106 case RELKIND_PARTITIONED_TABLE:
4107 appendStringInfo(buffer, _("table %s"),
4108 relname);
4109 break;
4110 case RELKIND_INDEX:
4111 case RELKIND_PARTITIONED_INDEX:
4112 appendStringInfo(buffer, _("index %s"),
4113 relname);
4114 break;
4115 case RELKIND_SEQUENCE:
4116 appendStringInfo(buffer, _("sequence %s"),
4117 relname);
4118 break;
4119 case RELKIND_TOASTVALUE:
4120 appendStringInfo(buffer, _("toast table %s"),
4121 relname);
4122 break;
4123 case RELKIND_VIEW:
4124 appendStringInfo(buffer, _("view %s"),
4125 relname);
4126 break;
4127 case RELKIND_MATVIEW:
4128 appendStringInfo(buffer, _("materialized view %s"),
4129 relname);
4130 break;
4131 case RELKIND_COMPOSITE_TYPE:
4132 appendStringInfo(buffer, _("composite type %s"),
4133 relname);
4134 break;
4135 case RELKIND_FOREIGN_TABLE:
4136 appendStringInfo(buffer, _("foreign table %s"),
4137 relname);
4138 break;
4139 default:
4140 /* shouldn't get here */
4141 appendStringInfo(buffer, _("relation %s"),
4142 relname);
4143 break;
4146 ReleaseSysCache(relTup);
4150 * subroutine for getObjectDescription: describe an operator family
4152 static void
4153 getOpFamilyDescription(StringInfo buffer, Oid opfid, bool missing_ok)
4155 HeapTuple opfTup;
4156 Form_pg_opfamily opfForm;
4157 HeapTuple amTup;
4158 Form_pg_am amForm;
4159 char *nspname;
4161 opfTup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfid));
4162 if (!HeapTupleIsValid(opfTup))
4164 if (!missing_ok)
4165 elog(ERROR, "cache lookup failed for opfamily %u", opfid);
4166 return;
4168 opfForm = (Form_pg_opfamily) GETSTRUCT(opfTup);
4170 amTup = SearchSysCache1(AMOID, ObjectIdGetDatum(opfForm->opfmethod));
4171 if (!HeapTupleIsValid(amTup))
4172 elog(ERROR, "cache lookup failed for access method %u",
4173 opfForm->opfmethod);
4174 amForm = (Form_pg_am) GETSTRUCT(amTup);
4176 /* Qualify the name if not visible in search path */
4177 if (OpfamilyIsVisible(opfid))
4178 nspname = NULL;
4179 else
4180 nspname = get_namespace_name(opfForm->opfnamespace);
4182 appendStringInfo(buffer, _("operator family %s for access method %s"),
4183 quote_qualified_identifier(nspname,
4184 NameStr(opfForm->opfname)),
4185 NameStr(amForm->amname));
4187 ReleaseSysCache(amTup);
4188 ReleaseSysCache(opfTup);
4192 * SQL-level callable version of getObjectDescription
4194 Datum
4195 pg_describe_object(PG_FUNCTION_ARGS)
4197 Oid classid = PG_GETARG_OID(0);
4198 Oid objid = PG_GETARG_OID(1);
4199 int32 objsubid = PG_GETARG_INT32(2);
4200 char *description;
4201 ObjectAddress address;
4203 /* for "pinned" items in pg_depend, return null */
4204 if (!OidIsValid(classid) && !OidIsValid(objid))
4205 PG_RETURN_NULL();
4207 address.classId = classid;
4208 address.objectId = objid;
4209 address.objectSubId = objsubid;
4211 description = getObjectDescription(&address, true);
4213 if (description == NULL)
4214 PG_RETURN_NULL();
4216 PG_RETURN_TEXT_P(cstring_to_text(description));
4220 * SQL-level callable function to obtain object type + identity
4222 Datum
4223 pg_identify_object(PG_FUNCTION_ARGS)
4225 Oid classid = PG_GETARG_OID(0);
4226 Oid objid = PG_GETARG_OID(1);
4227 int32 objsubid = PG_GETARG_INT32(2);
4228 Oid schema_oid = InvalidOid;
4229 const char *objname = NULL;
4230 char *objidentity;
4231 ObjectAddress address;
4232 Datum values[4];
4233 bool nulls[4];
4234 TupleDesc tupdesc;
4235 HeapTuple htup;
4237 address.classId = classid;
4238 address.objectId = objid;
4239 address.objectSubId = objsubid;
4242 * Construct a tuple descriptor for the result row. This must match this
4243 * function's pg_proc entry!
4245 tupdesc = CreateTemplateTupleDesc(4);
4246 TupleDescInitEntry(tupdesc, (AttrNumber) 1, "type",
4247 TEXTOID, -1, 0);
4248 TupleDescInitEntry(tupdesc, (AttrNumber) 2, "schema",
4249 TEXTOID, -1, 0);
4250 TupleDescInitEntry(tupdesc, (AttrNumber) 3, "name",
4251 TEXTOID, -1, 0);
4252 TupleDescInitEntry(tupdesc, (AttrNumber) 4, "identity",
4253 TEXTOID, -1, 0);
4255 tupdesc = BlessTupleDesc(tupdesc);
4257 if (is_objectclass_supported(address.classId))
4259 HeapTuple objtup;
4260 Relation catalog = table_open(address.classId, AccessShareLock);
4262 objtup = get_catalog_object_by_oid(catalog,
4263 get_object_attnum_oid(address.classId),
4264 address.objectId);
4265 if (objtup != NULL)
4267 bool isnull;
4268 AttrNumber nspAttnum;
4269 AttrNumber nameAttnum;
4271 nspAttnum = get_object_attnum_namespace(address.classId);
4272 if (nspAttnum != InvalidAttrNumber)
4274 schema_oid = heap_getattr(objtup, nspAttnum,
4275 RelationGetDescr(catalog), &isnull);
4276 if (isnull)
4277 elog(ERROR, "invalid null namespace in object %u/%u/%d",
4278 address.classId, address.objectId, address.objectSubId);
4282 * We only return the object name if it can be used (together with
4283 * the schema name, if any) as a unique identifier.
4285 if (get_object_namensp_unique(address.classId))
4287 nameAttnum = get_object_attnum_name(address.classId);
4288 if (nameAttnum != InvalidAttrNumber)
4290 Datum nameDatum;
4292 nameDatum = heap_getattr(objtup, nameAttnum,
4293 RelationGetDescr(catalog), &isnull);
4294 if (isnull)
4295 elog(ERROR, "invalid null name in object %u/%u/%d",
4296 address.classId, address.objectId, address.objectSubId);
4297 objname = quote_identifier(NameStr(*(DatumGetName(nameDatum))));
4302 table_close(catalog, AccessShareLock);
4305 /* object type, which can never be NULL */
4306 values[0] = CStringGetTextDatum(getObjectTypeDescription(&address, true));
4307 nulls[0] = false;
4310 * Before doing anything, extract the object identity. If the identity
4311 * could not be found, set all the fields except the object type to NULL.
4313 objidentity = getObjectIdentity(&address, true);
4315 /* schema name */
4316 if (OidIsValid(schema_oid) && objidentity)
4318 const char *schema = quote_identifier(get_namespace_name(schema_oid));
4320 values[1] = CStringGetTextDatum(schema);
4321 nulls[1] = false;
4323 else
4324 nulls[1] = true;
4326 /* object name */
4327 if (objname && objidentity)
4329 values[2] = CStringGetTextDatum(objname);
4330 nulls[2] = false;
4332 else
4333 nulls[2] = true;
4335 /* object identity */
4336 if (objidentity)
4338 values[3] = CStringGetTextDatum(objidentity);
4339 nulls[3] = false;
4341 else
4342 nulls[3] = true;
4344 htup = heap_form_tuple(tupdesc, values, nulls);
4346 PG_RETURN_DATUM(HeapTupleGetDatum(htup));
4350 * SQL-level callable function to obtain object type + identity
4352 Datum
4353 pg_identify_object_as_address(PG_FUNCTION_ARGS)
4355 Oid classid = PG_GETARG_OID(0);
4356 Oid objid = PG_GETARG_OID(1);
4357 int32 objsubid = PG_GETARG_INT32(2);
4358 ObjectAddress address;
4359 char *identity;
4360 List *names;
4361 List *args;
4362 Datum values[3];
4363 bool nulls[3];
4364 TupleDesc tupdesc;
4365 HeapTuple htup;
4367 address.classId = classid;
4368 address.objectId = objid;
4369 address.objectSubId = objsubid;
4372 * Construct a tuple descriptor for the result row. This must match this
4373 * function's pg_proc entry!
4375 tupdesc = CreateTemplateTupleDesc(3);
4376 TupleDescInitEntry(tupdesc, (AttrNumber) 1, "type",
4377 TEXTOID, -1, 0);
4378 TupleDescInitEntry(tupdesc, (AttrNumber) 2, "object_names",
4379 TEXTARRAYOID, -1, 0);
4380 TupleDescInitEntry(tupdesc, (AttrNumber) 3, "object_args",
4381 TEXTARRAYOID, -1, 0);
4383 tupdesc = BlessTupleDesc(tupdesc);
4385 /* object type, which can never be NULL */
4386 values[0] = CStringGetTextDatum(getObjectTypeDescription(&address, true));
4387 nulls[0] = false;
4389 /* object identity */
4390 identity = getObjectIdentityParts(&address, &names, &args, true);
4391 if (identity == NULL)
4393 nulls[1] = true;
4394 nulls[2] = true;
4396 else
4398 pfree(identity);
4400 /* object_names */
4401 if (names != NIL)
4402 values[1] = PointerGetDatum(strlist_to_textarray(names));
4403 else
4404 values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
4405 nulls[1] = false;
4407 /* object_args */
4408 if (args)
4409 values[2] = PointerGetDatum(strlist_to_textarray(args));
4410 else
4411 values[2] = PointerGetDatum(construct_empty_array(TEXTOID));
4412 nulls[2] = false;
4415 htup = heap_form_tuple(tupdesc, values, nulls);
4417 PG_RETURN_DATUM(HeapTupleGetDatum(htup));
4421 * Return a palloc'ed string that describes the type of object that the
4422 * passed address is for.
4424 * Keep ObjectTypeMap in sync with this.
4426 char *
4427 getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
4429 StringInfoData buffer;
4431 initStringInfo(&buffer);
4433 switch (getObjectClass(object))
4435 case OCLASS_CLASS:
4436 getRelationTypeDescription(&buffer, object->objectId,
4437 object->objectSubId,
4438 missing_ok);
4439 break;
4441 case OCLASS_PROC:
4442 getProcedureTypeDescription(&buffer, object->objectId,
4443 missing_ok);
4444 break;
4446 case OCLASS_TYPE:
4447 appendStringInfoString(&buffer, "type");
4448 break;
4450 case OCLASS_CAST:
4451 appendStringInfoString(&buffer, "cast");
4452 break;
4454 case OCLASS_COLLATION:
4455 appendStringInfoString(&buffer, "collation");
4456 break;
4458 case OCLASS_CONSTRAINT:
4459 getConstraintTypeDescription(&buffer, object->objectId,
4460 missing_ok);
4461 break;
4463 case OCLASS_CONVERSION:
4464 appendStringInfoString(&buffer, "conversion");
4465 break;
4467 case OCLASS_DEFAULT:
4468 appendStringInfoString(&buffer, "default value");
4469 break;
4471 case OCLASS_LANGUAGE:
4472 appendStringInfoString(&buffer, "language");
4473 break;
4475 case OCLASS_LARGEOBJECT:
4476 appendStringInfoString(&buffer, "large object");
4477 break;
4479 case OCLASS_OPERATOR:
4480 appendStringInfoString(&buffer, "operator");
4481 break;
4483 case OCLASS_OPCLASS:
4484 appendStringInfoString(&buffer, "operator class");
4485 break;
4487 case OCLASS_OPFAMILY:
4488 appendStringInfoString(&buffer, "operator family");
4489 break;
4491 case OCLASS_AM:
4492 appendStringInfoString(&buffer, "access method");
4493 break;
4495 case OCLASS_AMOP:
4496 appendStringInfoString(&buffer, "operator of access method");
4497 break;
4499 case OCLASS_AMPROC:
4500 appendStringInfoString(&buffer, "function of access method");
4501 break;
4503 case OCLASS_REWRITE:
4504 appendStringInfoString(&buffer, "rule");
4505 break;
4507 case OCLASS_TRIGGER:
4508 appendStringInfoString(&buffer, "trigger");
4509 break;
4511 case OCLASS_SCHEMA:
4512 appendStringInfoString(&buffer, "schema");
4513 break;
4515 case OCLASS_STATISTIC_EXT:
4516 appendStringInfoString(&buffer, "statistics object");
4517 break;
4519 case OCLASS_TSPARSER:
4520 appendStringInfoString(&buffer, "text search parser");
4521 break;
4523 case OCLASS_TSDICT:
4524 appendStringInfoString(&buffer, "text search dictionary");
4525 break;
4527 case OCLASS_TSTEMPLATE:
4528 appendStringInfoString(&buffer, "text search template");
4529 break;
4531 case OCLASS_TSCONFIG:
4532 appendStringInfoString(&buffer, "text search configuration");
4533 break;
4535 case OCLASS_ROLE:
4536 appendStringInfoString(&buffer, "role");
4537 break;
4539 case OCLASS_ROLE_MEMBERSHIP:
4540 appendStringInfoString(&buffer, "role membership");
4541 break;
4543 case OCLASS_DATABASE:
4544 appendStringInfoString(&buffer, "database");
4545 break;
4547 case OCLASS_TBLSPACE:
4548 appendStringInfoString(&buffer, "tablespace");
4549 break;
4551 case OCLASS_FDW:
4552 appendStringInfoString(&buffer, "foreign-data wrapper");
4553 break;
4555 case OCLASS_FOREIGN_SERVER:
4556 appendStringInfoString(&buffer, "server");
4557 break;
4559 case OCLASS_USER_MAPPING:
4560 appendStringInfoString(&buffer, "user mapping");
4561 break;
4563 case OCLASS_DEFACL:
4564 appendStringInfoString(&buffer, "default acl");
4565 break;
4567 case OCLASS_EXTENSION:
4568 appendStringInfoString(&buffer, "extension");
4569 break;
4571 case OCLASS_EVENT_TRIGGER:
4572 appendStringInfoString(&buffer, "event trigger");
4573 break;
4575 case OCLASS_PARAMETER_ACL:
4576 appendStringInfoString(&buffer, "parameter ACL");
4577 break;
4579 case OCLASS_POLICY:
4580 appendStringInfoString(&buffer, "policy");
4581 break;
4583 case OCLASS_PUBLICATION:
4584 appendStringInfoString(&buffer, "publication");
4585 break;
4587 case OCLASS_PUBLICATION_NAMESPACE:
4588 appendStringInfoString(&buffer, "publication namespace");
4589 break;
4591 case OCLASS_PUBLICATION_REL:
4592 appendStringInfoString(&buffer, "publication relation");
4593 break;
4595 case OCLASS_SUBSCRIPTION:
4596 appendStringInfoString(&buffer, "subscription");
4597 break;
4599 case OCLASS_TRANSFORM:
4600 appendStringInfoString(&buffer, "transform");
4601 break;
4604 * There's intentionally no default: case here; we want the
4605 * compiler to warn if a new OCLASS hasn't been handled above.
4609 /* the result can never be empty */
4610 Assert(buffer.len > 0);
4612 return buffer.data;
4616 * subroutine for getObjectTypeDescription: describe a relation type
4618 static void
4619 getRelationTypeDescription(StringInfo buffer, Oid relid, int32 objectSubId,
4620 bool missing_ok)
4622 HeapTuple relTup;
4623 Form_pg_class relForm;
4625 relTup = SearchSysCache1(RELOID,
4626 ObjectIdGetDatum(relid));
4627 if (!HeapTupleIsValid(relTup))
4629 if (!missing_ok)
4630 elog(ERROR, "cache lookup failed for relation %u", relid);
4632 /* fallback to "relation" for an undefined object */
4633 appendStringInfoString(buffer, "relation");
4634 return;
4636 relForm = (Form_pg_class) GETSTRUCT(relTup);
4638 switch (relForm->relkind)
4640 case RELKIND_RELATION:
4641 case RELKIND_PARTITIONED_TABLE:
4642 appendStringInfoString(buffer, "table");
4643 break;
4644 case RELKIND_INDEX:
4645 case RELKIND_PARTITIONED_INDEX:
4646 appendStringInfoString(buffer, "index");
4647 break;
4648 case RELKIND_SEQUENCE:
4649 appendStringInfoString(buffer, "sequence");
4650 break;
4651 case RELKIND_TOASTVALUE:
4652 appendStringInfoString(buffer, "toast table");
4653 break;
4654 case RELKIND_VIEW:
4655 appendStringInfoString(buffer, "view");
4656 break;
4657 case RELKIND_MATVIEW:
4658 appendStringInfoString(buffer, "materialized view");
4659 break;
4660 case RELKIND_COMPOSITE_TYPE:
4661 appendStringInfoString(buffer, "composite type");
4662 break;
4663 case RELKIND_FOREIGN_TABLE:
4664 appendStringInfoString(buffer, "foreign table");
4665 break;
4666 default:
4667 /* shouldn't get here */
4668 appendStringInfoString(buffer, "relation");
4669 break;
4672 if (objectSubId != 0)
4673 appendStringInfoString(buffer, " column");
4675 ReleaseSysCache(relTup);
4679 * subroutine for getObjectTypeDescription: describe a constraint type
4681 static void
4682 getConstraintTypeDescription(StringInfo buffer, Oid constroid, bool missing_ok)
4684 Relation constrRel;
4685 HeapTuple constrTup;
4686 Form_pg_constraint constrForm;
4688 constrRel = table_open(ConstraintRelationId, AccessShareLock);
4689 constrTup = get_catalog_object_by_oid(constrRel, Anum_pg_constraint_oid,
4690 constroid);
4691 if (!HeapTupleIsValid(constrTup))
4693 if (!missing_ok)
4694 elog(ERROR, "cache lookup failed for constraint %u", constroid);
4696 table_close(constrRel, AccessShareLock);
4698 /* fallback to "constraint" for an undefined object */
4699 appendStringInfoString(buffer, "constraint");
4700 return;
4703 constrForm = (Form_pg_constraint) GETSTRUCT(constrTup);
4705 if (OidIsValid(constrForm->conrelid))
4706 appendStringInfoString(buffer, "table constraint");
4707 else if (OidIsValid(constrForm->contypid))
4708 appendStringInfoString(buffer, "domain constraint");
4709 else
4710 elog(ERROR, "invalid constraint %u", constrForm->oid);
4712 table_close(constrRel, AccessShareLock);
4716 * subroutine for getObjectTypeDescription: describe a procedure type
4718 static void
4719 getProcedureTypeDescription(StringInfo buffer, Oid procid,
4720 bool missing_ok)
4722 HeapTuple procTup;
4723 Form_pg_proc procForm;
4725 procTup = SearchSysCache1(PROCOID,
4726 ObjectIdGetDatum(procid));
4727 if (!HeapTupleIsValid(procTup))
4729 if (!missing_ok)
4730 elog(ERROR, "cache lookup failed for procedure %u", procid);
4732 /* fallback to "procedure" for an undefined object */
4733 appendStringInfoString(buffer, "routine");
4734 return;
4736 procForm = (Form_pg_proc) GETSTRUCT(procTup);
4738 if (procForm->prokind == PROKIND_AGGREGATE)
4739 appendStringInfoString(buffer, "aggregate");
4740 else if (procForm->prokind == PROKIND_PROCEDURE)
4741 appendStringInfoString(buffer, "procedure");
4742 else /* function or window function */
4743 appendStringInfoString(buffer, "function");
4745 ReleaseSysCache(procTup);
4749 * Obtain a given object's identity, as a palloc'ed string.
4751 * This is for machine consumption, so it's not translated. All elements are
4752 * schema-qualified when appropriate. Returns NULL if the object could not
4753 * be found.
4755 char *
4756 getObjectIdentity(const ObjectAddress *object, bool missing_ok)
4758 return getObjectIdentityParts(object, NULL, NULL, missing_ok);
4762 * As above, but more detailed.
4764 * There are two sets of return values: the identity itself as a palloc'd
4765 * string is returned. objname and objargs, if not NULL, are output parameters
4766 * that receive lists of C-strings that are useful to give back to
4767 * get_object_address() to reconstruct the ObjectAddress. Returns NULL if
4768 * the object could not be found.
4770 char *
4771 getObjectIdentityParts(const ObjectAddress *object,
4772 List **objname, List **objargs,
4773 bool missing_ok)
4775 StringInfoData buffer;
4777 initStringInfo(&buffer);
4780 * Make sure that both objname and objargs were passed, or none was; and
4781 * initialize them to empty lists. For objname this is useless because it
4782 * will be initialized in all cases inside the switch; but we do it anyway
4783 * so that we can test below that no branch leaves it unset.
4785 Assert(PointerIsValid(objname) == PointerIsValid(objargs));
4786 if (objname)
4788 *objname = NIL;
4789 *objargs = NIL;
4792 switch (getObjectClass(object))
4794 case OCLASS_CLASS:
4796 char *attr = NULL;
4799 * Check for the attribute first, so as if it is missing we
4800 * can skip the entire relation description.
4802 if (object->objectSubId != 0)
4804 attr = get_attname(object->objectId,
4805 object->objectSubId,
4806 missing_ok);
4808 if (missing_ok && attr == NULL)
4809 break;
4812 getRelationIdentity(&buffer, object->objectId, objname,
4813 missing_ok);
4814 if (objname && *objname == NIL)
4815 break;
4817 if (attr)
4819 appendStringInfo(&buffer, ".%s",
4820 quote_identifier(attr));
4821 if (objname)
4822 *objname = lappend(*objname, attr);
4825 break;
4827 case OCLASS_PROC:
4829 bits16 flags = FORMAT_PROC_FORCE_QUALIFY | FORMAT_PROC_INVALID_AS_NULL;
4830 char *proname = format_procedure_extended(object->objectId,
4831 flags);
4833 if (proname == NULL)
4834 break;
4836 appendStringInfoString(&buffer, proname);
4837 if (objname)
4838 format_procedure_parts(object->objectId, objname, objargs,
4839 missing_ok);
4840 break;
4843 case OCLASS_TYPE:
4845 bits16 flags = FORMAT_TYPE_INVALID_AS_NULL | FORMAT_TYPE_FORCE_QUALIFY;
4846 char *typeout;
4848 typeout = format_type_extended(object->objectId, -1, flags);
4850 if (typeout == NULL)
4851 break;
4853 appendStringInfoString(&buffer, typeout);
4854 if (objname)
4855 *objname = list_make1(typeout);
4857 break;
4859 case OCLASS_CAST:
4861 Relation castRel;
4862 HeapTuple tup;
4863 Form_pg_cast castForm;
4865 castRel = table_open(CastRelationId, AccessShareLock);
4867 tup = get_catalog_object_by_oid(castRel, Anum_pg_cast_oid,
4868 object->objectId);
4870 if (!HeapTupleIsValid(tup))
4872 if (!missing_ok)
4873 elog(ERROR, "could not find tuple for cast %u",
4874 object->objectId);
4876 table_close(castRel, AccessShareLock);
4877 break;
4880 castForm = (Form_pg_cast) GETSTRUCT(tup);
4882 appendStringInfo(&buffer, "(%s AS %s)",
4883 format_type_be_qualified(castForm->castsource),
4884 format_type_be_qualified(castForm->casttarget));
4886 if (objname)
4888 *objname = list_make1(format_type_be_qualified(castForm->castsource));
4889 *objargs = list_make1(format_type_be_qualified(castForm->casttarget));
4892 table_close(castRel, AccessShareLock);
4893 break;
4896 case OCLASS_COLLATION:
4898 HeapTuple collTup;
4899 Form_pg_collation coll;
4900 char *schema;
4902 collTup = SearchSysCache1(COLLOID,
4903 ObjectIdGetDatum(object->objectId));
4904 if (!HeapTupleIsValid(collTup))
4906 if (!missing_ok)
4907 elog(ERROR, "cache lookup failed for collation %u",
4908 object->objectId);
4909 break;
4911 coll = (Form_pg_collation) GETSTRUCT(collTup);
4912 schema = get_namespace_name_or_temp(coll->collnamespace);
4913 appendStringInfoString(&buffer,
4914 quote_qualified_identifier(schema,
4915 NameStr(coll->collname)));
4916 if (objname)
4917 *objname = list_make2(schema,
4918 pstrdup(NameStr(coll->collname)));
4919 ReleaseSysCache(collTup);
4920 break;
4923 case OCLASS_CONSTRAINT:
4925 HeapTuple conTup;
4926 Form_pg_constraint con;
4928 conTup = SearchSysCache1(CONSTROID,
4929 ObjectIdGetDatum(object->objectId));
4930 if (!HeapTupleIsValid(conTup))
4932 if (!missing_ok)
4933 elog(ERROR, "cache lookup failed for constraint %u",
4934 object->objectId);
4935 break;
4937 con = (Form_pg_constraint) GETSTRUCT(conTup);
4939 if (OidIsValid(con->conrelid))
4941 appendStringInfo(&buffer, "%s on ",
4942 quote_identifier(NameStr(con->conname)));
4943 getRelationIdentity(&buffer, con->conrelid, objname,
4944 false);
4945 if (objname)
4946 *objname = lappend(*objname, pstrdup(NameStr(con->conname)));
4948 else
4950 ObjectAddress domain;
4952 Assert(OidIsValid(con->contypid));
4953 domain.classId = TypeRelationId;
4954 domain.objectId = con->contypid;
4955 domain.objectSubId = 0;
4957 appendStringInfo(&buffer, "%s on %s",
4958 quote_identifier(NameStr(con->conname)),
4959 getObjectIdentityParts(&domain, objname,
4960 objargs, false));
4962 if (objname)
4963 *objargs = lappend(*objargs, pstrdup(NameStr(con->conname)));
4966 ReleaseSysCache(conTup);
4967 break;
4970 case OCLASS_CONVERSION:
4972 HeapTuple conTup;
4973 Form_pg_conversion conForm;
4974 char *schema;
4976 conTup = SearchSysCache1(CONVOID,
4977 ObjectIdGetDatum(object->objectId));
4978 if (!HeapTupleIsValid(conTup))
4980 if (!missing_ok)
4981 elog(ERROR, "cache lookup failed for conversion %u",
4982 object->objectId);
4983 break;
4985 conForm = (Form_pg_conversion) GETSTRUCT(conTup);
4986 schema = get_namespace_name_or_temp(conForm->connamespace);
4987 appendStringInfoString(&buffer,
4988 quote_qualified_identifier(schema,
4989 NameStr(conForm->conname)));
4990 if (objname)
4991 *objname = list_make2(schema,
4992 pstrdup(NameStr(conForm->conname)));
4993 ReleaseSysCache(conTup);
4994 break;
4997 case OCLASS_DEFAULT:
4999 ObjectAddress colobject;
5001 colobject = GetAttrDefaultColumnAddress(object->objectId);
5003 if (!OidIsValid(colobject.objectId))
5005 if (!missing_ok)
5006 elog(ERROR, "could not find tuple for attrdef %u",
5007 object->objectId);
5008 break;
5011 appendStringInfo(&buffer, "for %s",
5012 getObjectIdentityParts(&colobject,
5013 objname, objargs,
5014 false));
5015 break;
5018 case OCLASS_LANGUAGE:
5020 HeapTuple langTup;
5021 Form_pg_language langForm;
5023 langTup = SearchSysCache1(LANGOID,
5024 ObjectIdGetDatum(object->objectId));
5025 if (!HeapTupleIsValid(langTup))
5027 if (!missing_ok)
5028 elog(ERROR, "cache lookup failed for language %u",
5029 object->objectId);
5030 break;
5032 langForm = (Form_pg_language) GETSTRUCT(langTup);
5033 appendStringInfoString(&buffer,
5034 quote_identifier(NameStr(langForm->lanname)));
5035 if (objname)
5036 *objname = list_make1(pstrdup(NameStr(langForm->lanname)));
5037 ReleaseSysCache(langTup);
5038 break;
5040 case OCLASS_LARGEOBJECT:
5041 if (!LargeObjectExists(object->objectId))
5042 break;
5043 appendStringInfo(&buffer, "%u",
5044 object->objectId);
5045 if (objname)
5046 *objname = list_make1(psprintf("%u", object->objectId));
5047 break;
5049 case OCLASS_OPERATOR:
5051 bits16 flags = FORMAT_OPERATOR_FORCE_QUALIFY | FORMAT_OPERATOR_INVALID_AS_NULL;
5052 char *oprname = format_operator_extended(object->objectId,
5053 flags);
5055 if (oprname == NULL)
5056 break;
5058 appendStringInfoString(&buffer, oprname);
5059 if (objname)
5060 format_operator_parts(object->objectId, objname, objargs, missing_ok);
5061 break;
5064 case OCLASS_OPCLASS:
5066 HeapTuple opcTup;
5067 Form_pg_opclass opcForm;
5068 HeapTuple amTup;
5069 Form_pg_am amForm;
5070 char *schema;
5072 opcTup = SearchSysCache1(CLAOID,
5073 ObjectIdGetDatum(object->objectId));
5074 if (!HeapTupleIsValid(opcTup))
5076 if (!missing_ok)
5077 elog(ERROR, "cache lookup failed for opclass %u",
5078 object->objectId);
5079 break;
5081 opcForm = (Form_pg_opclass) GETSTRUCT(opcTup);
5082 schema = get_namespace_name_or_temp(opcForm->opcnamespace);
5084 amTup = SearchSysCache1(AMOID,
5085 ObjectIdGetDatum(opcForm->opcmethod));
5086 if (!HeapTupleIsValid(amTup))
5087 elog(ERROR, "cache lookup failed for access method %u",
5088 opcForm->opcmethod);
5089 amForm = (Form_pg_am) GETSTRUCT(amTup);
5091 appendStringInfo(&buffer, "%s USING %s",
5092 quote_qualified_identifier(schema,
5093 NameStr(opcForm->opcname)),
5094 quote_identifier(NameStr(amForm->amname)));
5095 if (objname)
5096 *objname = list_make3(pstrdup(NameStr(amForm->amname)),
5097 schema,
5098 pstrdup(NameStr(opcForm->opcname)));
5100 ReleaseSysCache(amTup);
5101 ReleaseSysCache(opcTup);
5102 break;
5105 case OCLASS_OPFAMILY:
5106 getOpFamilyIdentity(&buffer, object->objectId, objname,
5107 missing_ok);
5108 break;
5110 case OCLASS_AM:
5112 char *amname;
5114 amname = get_am_name(object->objectId);
5115 if (!amname)
5117 if (!missing_ok)
5118 elog(ERROR, "cache lookup failed for access method %u",
5119 object->objectId);
5120 break;
5122 appendStringInfoString(&buffer, quote_identifier(amname));
5123 if (objname)
5124 *objname = list_make1(amname);
5126 break;
5128 case OCLASS_AMOP:
5130 Relation amopDesc;
5131 HeapTuple tup;
5132 ScanKeyData skey[1];
5133 SysScanDesc amscan;
5134 Form_pg_amop amopForm;
5135 StringInfoData opfam;
5136 char *ltype;
5137 char *rtype;
5139 amopDesc = table_open(AccessMethodOperatorRelationId,
5140 AccessShareLock);
5142 ScanKeyInit(&skey[0],
5143 Anum_pg_amop_oid,
5144 BTEqualStrategyNumber, F_OIDEQ,
5145 ObjectIdGetDatum(object->objectId));
5147 amscan = systable_beginscan(amopDesc, AccessMethodOperatorOidIndexId, true,
5148 NULL, 1, skey);
5150 tup = systable_getnext(amscan);
5152 if (!HeapTupleIsValid(tup))
5154 if (!missing_ok)
5155 elog(ERROR, "could not find tuple for amop entry %u",
5156 object->objectId);
5158 systable_endscan(amscan);
5159 table_close(amopDesc, AccessShareLock);
5160 break;
5163 amopForm = (Form_pg_amop) GETSTRUCT(tup);
5165 initStringInfo(&opfam);
5166 getOpFamilyIdentity(&opfam, amopForm->amopfamily, objname,
5167 false);
5169 ltype = format_type_be_qualified(amopForm->amoplefttype);
5170 rtype = format_type_be_qualified(amopForm->amoprighttype);
5172 if (objname)
5174 *objname = lappend(*objname,
5175 psprintf("%d", amopForm->amopstrategy));
5176 *objargs = list_make2(ltype, rtype);
5179 appendStringInfo(&buffer, "operator %d (%s, %s) of %s",
5180 amopForm->amopstrategy,
5181 ltype, rtype, opfam.data);
5183 pfree(opfam.data);
5185 systable_endscan(amscan);
5186 table_close(amopDesc, AccessShareLock);
5187 break;
5190 case OCLASS_AMPROC:
5192 Relation amprocDesc;
5193 ScanKeyData skey[1];
5194 SysScanDesc amscan;
5195 HeapTuple tup;
5196 Form_pg_amproc amprocForm;
5197 StringInfoData opfam;
5198 char *ltype;
5199 char *rtype;
5201 amprocDesc = table_open(AccessMethodProcedureRelationId,
5202 AccessShareLock);
5204 ScanKeyInit(&skey[0],
5205 Anum_pg_amproc_oid,
5206 BTEqualStrategyNumber, F_OIDEQ,
5207 ObjectIdGetDatum(object->objectId));
5209 amscan = systable_beginscan(amprocDesc, AccessMethodProcedureOidIndexId, true,
5210 NULL, 1, skey);
5212 tup = systable_getnext(amscan);
5214 if (!HeapTupleIsValid(tup))
5216 if (!missing_ok)
5217 elog(ERROR, "could not find tuple for amproc entry %u",
5218 object->objectId);
5220 systable_endscan(amscan);
5221 table_close(amprocDesc, AccessShareLock);
5222 break;
5225 amprocForm = (Form_pg_amproc) GETSTRUCT(tup);
5227 initStringInfo(&opfam);
5228 getOpFamilyIdentity(&opfam, amprocForm->amprocfamily, objname,
5229 false);
5231 ltype = format_type_be_qualified(amprocForm->amproclefttype);
5232 rtype = format_type_be_qualified(amprocForm->amprocrighttype);
5234 if (objname)
5236 *objname = lappend(*objname,
5237 psprintf("%d", amprocForm->amprocnum));
5238 *objargs = list_make2(ltype, rtype);
5241 appendStringInfo(&buffer, "function %d (%s, %s) of %s",
5242 amprocForm->amprocnum,
5243 ltype, rtype, opfam.data);
5245 pfree(opfam.data);
5247 systable_endscan(amscan);
5248 table_close(amprocDesc, AccessShareLock);
5249 break;
5252 case OCLASS_REWRITE:
5254 Relation ruleDesc;
5255 HeapTuple tup;
5256 Form_pg_rewrite rule;
5258 ruleDesc = table_open(RewriteRelationId, AccessShareLock);
5260 tup = get_catalog_object_by_oid(ruleDesc, Anum_pg_rewrite_oid,
5261 object->objectId);
5263 if (!HeapTupleIsValid(tup))
5265 if (!missing_ok)
5266 elog(ERROR, "could not find tuple for rule %u",
5267 object->objectId);
5269 table_close(ruleDesc, AccessShareLock);
5270 break;
5273 rule = (Form_pg_rewrite) GETSTRUCT(tup);
5275 appendStringInfo(&buffer, "%s on ",
5276 quote_identifier(NameStr(rule->rulename)));
5277 getRelationIdentity(&buffer, rule->ev_class, objname, false);
5278 if (objname)
5279 *objname = lappend(*objname, pstrdup(NameStr(rule->rulename)));
5281 table_close(ruleDesc, AccessShareLock);
5282 break;
5285 case OCLASS_TRIGGER:
5287 Relation trigDesc;
5288 HeapTuple tup;
5289 Form_pg_trigger trig;
5291 trigDesc = table_open(TriggerRelationId, AccessShareLock);
5293 tup = get_catalog_object_by_oid(trigDesc, Anum_pg_trigger_oid,
5294 object->objectId);
5296 if (!HeapTupleIsValid(tup))
5298 if (!missing_ok)
5299 elog(ERROR, "could not find tuple for trigger %u",
5300 object->objectId);
5302 table_close(trigDesc, AccessShareLock);
5303 break;
5306 trig = (Form_pg_trigger) GETSTRUCT(tup);
5308 appendStringInfo(&buffer, "%s on ",
5309 quote_identifier(NameStr(trig->tgname)));
5310 getRelationIdentity(&buffer, trig->tgrelid, objname, false);
5311 if (objname)
5312 *objname = lappend(*objname, pstrdup(NameStr(trig->tgname)));
5314 table_close(trigDesc, AccessShareLock);
5315 break;
5318 case OCLASS_SCHEMA:
5320 char *nspname;
5322 nspname = get_namespace_name_or_temp(object->objectId);
5323 if (!nspname)
5325 if (!missing_ok)
5326 elog(ERROR, "cache lookup failed for namespace %u",
5327 object->objectId);
5328 break;
5330 appendStringInfoString(&buffer,
5331 quote_identifier(nspname));
5332 if (objname)
5333 *objname = list_make1(nspname);
5334 break;
5337 case OCLASS_STATISTIC_EXT:
5339 HeapTuple tup;
5340 Form_pg_statistic_ext formStatistic;
5341 char *schema;
5343 tup = SearchSysCache1(STATEXTOID,
5344 ObjectIdGetDatum(object->objectId));
5345 if (!HeapTupleIsValid(tup))
5347 if (!missing_ok)
5348 elog(ERROR, "cache lookup failed for statistics object %u",
5349 object->objectId);
5350 break;
5352 formStatistic = (Form_pg_statistic_ext) GETSTRUCT(tup);
5353 schema = get_namespace_name_or_temp(formStatistic->stxnamespace);
5354 appendStringInfoString(&buffer,
5355 quote_qualified_identifier(schema,
5356 NameStr(formStatistic->stxname)));
5357 if (objname)
5358 *objname = list_make2(schema,
5359 pstrdup(NameStr(formStatistic->stxname)));
5360 ReleaseSysCache(tup);
5362 break;
5364 case OCLASS_TSPARSER:
5366 HeapTuple tup;
5367 Form_pg_ts_parser formParser;
5368 char *schema;
5370 tup = SearchSysCache1(TSPARSEROID,
5371 ObjectIdGetDatum(object->objectId));
5372 if (!HeapTupleIsValid(tup))
5374 if (!missing_ok)
5375 elog(ERROR, "cache lookup failed for text search parser %u",
5376 object->objectId);
5377 break;
5379 formParser = (Form_pg_ts_parser) GETSTRUCT(tup);
5380 schema = get_namespace_name_or_temp(formParser->prsnamespace);
5381 appendStringInfoString(&buffer,
5382 quote_qualified_identifier(schema,
5383 NameStr(formParser->prsname)));
5384 if (objname)
5385 *objname = list_make2(schema,
5386 pstrdup(NameStr(formParser->prsname)));
5387 ReleaseSysCache(tup);
5388 break;
5391 case OCLASS_TSDICT:
5393 HeapTuple tup;
5394 Form_pg_ts_dict formDict;
5395 char *schema;
5397 tup = SearchSysCache1(TSDICTOID,
5398 ObjectIdGetDatum(object->objectId));
5399 if (!HeapTupleIsValid(tup))
5401 if (!missing_ok)
5402 elog(ERROR, "cache lookup failed for text search dictionary %u",
5403 object->objectId);
5404 break;
5406 formDict = (Form_pg_ts_dict) GETSTRUCT(tup);
5407 schema = get_namespace_name_or_temp(formDict->dictnamespace);
5408 appendStringInfoString(&buffer,
5409 quote_qualified_identifier(schema,
5410 NameStr(formDict->dictname)));
5411 if (objname)
5412 *objname = list_make2(schema,
5413 pstrdup(NameStr(formDict->dictname)));
5414 ReleaseSysCache(tup);
5415 break;
5418 case OCLASS_TSTEMPLATE:
5420 HeapTuple tup;
5421 Form_pg_ts_template formTmpl;
5422 char *schema;
5424 tup = SearchSysCache1(TSTEMPLATEOID,
5425 ObjectIdGetDatum(object->objectId));
5426 if (!HeapTupleIsValid(tup))
5428 if (!missing_ok)
5429 elog(ERROR, "cache lookup failed for text search template %u",
5430 object->objectId);
5431 break;
5433 formTmpl = (Form_pg_ts_template) GETSTRUCT(tup);
5434 schema = get_namespace_name_or_temp(formTmpl->tmplnamespace);
5435 appendStringInfoString(&buffer,
5436 quote_qualified_identifier(schema,
5437 NameStr(formTmpl->tmplname)));
5438 if (objname)
5439 *objname = list_make2(schema,
5440 pstrdup(NameStr(formTmpl->tmplname)));
5441 ReleaseSysCache(tup);
5442 break;
5445 case OCLASS_TSCONFIG:
5447 HeapTuple tup;
5448 Form_pg_ts_config formCfg;
5449 char *schema;
5451 tup = SearchSysCache1(TSCONFIGOID,
5452 ObjectIdGetDatum(object->objectId));
5453 if (!HeapTupleIsValid(tup))
5455 if (!missing_ok)
5456 elog(ERROR, "cache lookup failed for text search configuration %u",
5457 object->objectId);
5458 break;
5460 formCfg = (Form_pg_ts_config) GETSTRUCT(tup);
5461 schema = get_namespace_name_or_temp(formCfg->cfgnamespace);
5462 appendStringInfoString(&buffer,
5463 quote_qualified_identifier(schema,
5464 NameStr(formCfg->cfgname)));
5465 if (objname)
5466 *objname = list_make2(schema,
5467 pstrdup(NameStr(formCfg->cfgname)));
5468 ReleaseSysCache(tup);
5469 break;
5472 case OCLASS_ROLE:
5474 char *username;
5476 username = GetUserNameFromId(object->objectId, missing_ok);
5477 if (!username)
5478 break;
5479 if (objname)
5480 *objname = list_make1(username);
5481 appendStringInfoString(&buffer,
5482 quote_identifier(username));
5483 break;
5486 case OCLASS_ROLE_MEMBERSHIP:
5488 Relation authMemDesc;
5489 ScanKeyData skey[1];
5490 SysScanDesc amscan;
5491 HeapTuple tup;
5492 Form_pg_auth_members amForm;
5494 authMemDesc = table_open(AuthMemRelationId,
5495 AccessShareLock);
5497 ScanKeyInit(&skey[0],
5498 Anum_pg_auth_members_oid,
5499 BTEqualStrategyNumber, F_OIDEQ,
5500 ObjectIdGetDatum(object->objectId));
5502 amscan = systable_beginscan(authMemDesc, AuthMemOidIndexId, true,
5503 NULL, 1, skey);
5505 tup = systable_getnext(amscan);
5507 if (!HeapTupleIsValid(tup))
5509 if (!missing_ok)
5510 elog(ERROR, "could not find tuple for pg_auth_members entry %u",
5511 object->objectId);
5513 systable_endscan(amscan);
5514 table_close(authMemDesc, AccessShareLock);
5515 break;
5518 amForm = (Form_pg_auth_members) GETSTRUCT(tup);
5520 appendStringInfo(&buffer, _("membership of role %s in role %s"),
5521 GetUserNameFromId(amForm->member, false),
5522 GetUserNameFromId(amForm->roleid, false));
5524 systable_endscan(amscan);
5525 table_close(authMemDesc, AccessShareLock);
5526 break;
5529 case OCLASS_DATABASE:
5531 char *datname;
5533 datname = get_database_name(object->objectId);
5534 if (!datname)
5536 if (!missing_ok)
5537 elog(ERROR, "cache lookup failed for database %u",
5538 object->objectId);
5539 break;
5541 if (objname)
5542 *objname = list_make1(datname);
5543 appendStringInfoString(&buffer,
5544 quote_identifier(datname));
5545 break;
5548 case OCLASS_TBLSPACE:
5550 char *tblspace;
5552 tblspace = get_tablespace_name(object->objectId);
5553 if (!tblspace)
5555 if (!missing_ok)
5556 elog(ERROR, "cache lookup failed for tablespace %u",
5557 object->objectId);
5558 break;
5560 if (objname)
5561 *objname = list_make1(tblspace);
5562 appendStringInfoString(&buffer,
5563 quote_identifier(tblspace));
5564 break;
5567 case OCLASS_FDW:
5569 ForeignDataWrapper *fdw;
5571 fdw = GetForeignDataWrapperExtended(object->objectId,
5572 missing_ok);
5573 if (fdw)
5575 appendStringInfoString(&buffer, quote_identifier(fdw->fdwname));
5576 if (objname)
5577 *objname = list_make1(pstrdup(fdw->fdwname));
5579 break;
5582 case OCLASS_FOREIGN_SERVER:
5584 ForeignServer *srv;
5586 srv = GetForeignServerExtended(object->objectId,
5587 missing_ok);
5588 if (srv)
5590 appendStringInfoString(&buffer,
5591 quote_identifier(srv->servername));
5592 if (objname)
5593 *objname = list_make1(pstrdup(srv->servername));
5595 break;
5598 case OCLASS_USER_MAPPING:
5600 HeapTuple tup;
5601 Oid useid;
5602 Form_pg_user_mapping umform;
5603 ForeignServer *srv;
5604 const char *usename;
5606 tup = SearchSysCache1(USERMAPPINGOID,
5607 ObjectIdGetDatum(object->objectId));
5608 if (!HeapTupleIsValid(tup))
5610 if (!missing_ok)
5611 elog(ERROR, "cache lookup failed for user mapping %u",
5612 object->objectId);
5613 break;
5615 umform = (Form_pg_user_mapping) GETSTRUCT(tup);
5616 useid = umform->umuser;
5617 srv = GetForeignServer(umform->umserver);
5619 ReleaseSysCache(tup);
5621 if (OidIsValid(useid))
5622 usename = GetUserNameFromId(useid, false);
5623 else
5624 usename = "public";
5626 if (objname)
5628 *objname = list_make1(pstrdup(usename));
5629 *objargs = list_make1(pstrdup(srv->servername));
5632 appendStringInfo(&buffer, "%s on server %s",
5633 quote_identifier(usename),
5634 srv->servername);
5635 break;
5638 case OCLASS_DEFACL:
5640 Relation defaclrel;
5641 ScanKeyData skey[1];
5642 SysScanDesc rcscan;
5643 HeapTuple tup;
5644 Form_pg_default_acl defacl;
5645 char *schema;
5646 char *username;
5648 defaclrel = table_open(DefaultAclRelationId, AccessShareLock);
5650 ScanKeyInit(&skey[0],
5651 Anum_pg_default_acl_oid,
5652 BTEqualStrategyNumber, F_OIDEQ,
5653 ObjectIdGetDatum(object->objectId));
5655 rcscan = systable_beginscan(defaclrel, DefaultAclOidIndexId,
5656 true, NULL, 1, skey);
5658 tup = systable_getnext(rcscan);
5660 if (!HeapTupleIsValid(tup))
5662 if (!missing_ok)
5663 elog(ERROR, "could not find tuple for default ACL %u",
5664 object->objectId);
5666 systable_endscan(rcscan);
5667 table_close(defaclrel, AccessShareLock);
5668 break;
5671 defacl = (Form_pg_default_acl) GETSTRUCT(tup);
5673 username = GetUserNameFromId(defacl->defaclrole, false);
5674 appendStringInfo(&buffer,
5675 "for role %s",
5676 quote_identifier(username));
5678 if (OidIsValid(defacl->defaclnamespace))
5680 schema = get_namespace_name_or_temp(defacl->defaclnamespace);
5681 appendStringInfo(&buffer,
5682 " in schema %s",
5683 quote_identifier(schema));
5685 else
5686 schema = NULL;
5688 switch (defacl->defaclobjtype)
5690 case DEFACLOBJ_RELATION:
5691 appendStringInfoString(&buffer,
5692 " on tables");
5693 break;
5694 case DEFACLOBJ_SEQUENCE:
5695 appendStringInfoString(&buffer,
5696 " on sequences");
5697 break;
5698 case DEFACLOBJ_FUNCTION:
5699 appendStringInfoString(&buffer,
5700 " on functions");
5701 break;
5702 case DEFACLOBJ_TYPE:
5703 appendStringInfoString(&buffer,
5704 " on types");
5705 break;
5706 case DEFACLOBJ_NAMESPACE:
5707 appendStringInfoString(&buffer,
5708 " on schemas");
5709 break;
5712 if (objname)
5714 *objname = list_make1(username);
5715 if (schema)
5716 *objname = lappend(*objname, schema);
5717 *objargs = list_make1(psprintf("%c", defacl->defaclobjtype));
5720 systable_endscan(rcscan);
5721 table_close(defaclrel, AccessShareLock);
5722 break;
5725 case OCLASS_EXTENSION:
5727 char *extname;
5729 extname = get_extension_name(object->objectId);
5730 if (!extname)
5732 if (!missing_ok)
5733 elog(ERROR, "cache lookup failed for extension %u",
5734 object->objectId);
5735 break;
5737 appendStringInfoString(&buffer, quote_identifier(extname));
5738 if (objname)
5739 *objname = list_make1(extname);
5740 break;
5743 case OCLASS_EVENT_TRIGGER:
5745 HeapTuple tup;
5746 Form_pg_event_trigger trigForm;
5747 char *evtname;
5749 tup = SearchSysCache1(EVENTTRIGGEROID,
5750 ObjectIdGetDatum(object->objectId));
5751 if (!HeapTupleIsValid(tup))
5753 if (!missing_ok)
5754 elog(ERROR, "cache lookup failed for event trigger %u",
5755 object->objectId);
5756 break;
5758 trigForm = (Form_pg_event_trigger) GETSTRUCT(tup);
5759 evtname = pstrdup(NameStr(trigForm->evtname));
5760 appendStringInfoString(&buffer, quote_identifier(evtname));
5761 if (objname)
5762 *objname = list_make1(evtname);
5763 ReleaseSysCache(tup);
5764 break;
5767 case OCLASS_PARAMETER_ACL:
5769 HeapTuple tup;
5770 Datum nameDatum;
5771 bool isNull;
5772 char *parname;
5774 tup = SearchSysCache1(PARAMETERACLOID,
5775 ObjectIdGetDatum(object->objectId));
5776 if (!HeapTupleIsValid(tup))
5778 if (!missing_ok)
5779 elog(ERROR, "cache lookup failed for parameter ACL %u",
5780 object->objectId);
5781 break;
5783 nameDatum = SysCacheGetAttr(PARAMETERACLOID, tup,
5784 Anum_pg_parameter_acl_parname,
5785 &isNull);
5786 Assert(!isNull);
5787 parname = TextDatumGetCString(nameDatum);
5788 appendStringInfoString(&buffer, parname);
5789 if (objname)
5790 *objname = list_make1(parname);
5791 ReleaseSysCache(tup);
5792 break;
5795 case OCLASS_POLICY:
5797 Relation polDesc;
5798 HeapTuple tup;
5799 Form_pg_policy policy;
5801 polDesc = table_open(PolicyRelationId, AccessShareLock);
5803 tup = get_catalog_object_by_oid(polDesc, Anum_pg_policy_oid,
5804 object->objectId);
5806 if (!HeapTupleIsValid(tup))
5808 if (!missing_ok)
5809 elog(ERROR, "could not find tuple for policy %u",
5810 object->objectId);
5812 table_close(polDesc, AccessShareLock);
5813 break;
5816 policy = (Form_pg_policy) GETSTRUCT(tup);
5818 appendStringInfo(&buffer, "%s on ",
5819 quote_identifier(NameStr(policy->polname)));
5820 getRelationIdentity(&buffer, policy->polrelid, objname, false);
5821 if (objname)
5822 *objname = lappend(*objname, pstrdup(NameStr(policy->polname)));
5824 table_close(polDesc, AccessShareLock);
5825 break;
5828 case OCLASS_PUBLICATION:
5830 char *pubname;
5832 pubname = get_publication_name(object->objectId, missing_ok);
5833 if (pubname)
5835 appendStringInfoString(&buffer,
5836 quote_identifier(pubname));
5837 if (objname)
5838 *objname = list_make1(pubname);
5840 break;
5843 case OCLASS_PUBLICATION_NAMESPACE:
5845 char *pubname;
5846 char *nspname;
5848 if (!getPublicationSchemaInfo(object, missing_ok, &pubname,
5849 &nspname))
5850 break;
5851 appendStringInfo(&buffer, "%s in publication %s",
5852 nspname, pubname);
5854 if (objargs)
5855 *objargs = list_make1(pubname);
5856 else
5857 pfree(pubname);
5859 if (objname)
5860 *objname = list_make1(nspname);
5861 else
5862 pfree(nspname);
5864 break;
5867 case OCLASS_PUBLICATION_REL:
5869 HeapTuple tup;
5870 char *pubname;
5871 Form_pg_publication_rel prform;
5873 tup = SearchSysCache1(PUBLICATIONREL,
5874 ObjectIdGetDatum(object->objectId));
5875 if (!HeapTupleIsValid(tup))
5877 if (!missing_ok)
5878 elog(ERROR, "cache lookup failed for publication table %u",
5879 object->objectId);
5880 break;
5883 prform = (Form_pg_publication_rel) GETSTRUCT(tup);
5884 pubname = get_publication_name(prform->prpubid, false);
5886 getRelationIdentity(&buffer, prform->prrelid, objname, false);
5887 appendStringInfo(&buffer, " in publication %s", pubname);
5889 if (objargs)
5890 *objargs = list_make1(pubname);
5892 ReleaseSysCache(tup);
5893 break;
5896 case OCLASS_SUBSCRIPTION:
5898 char *subname;
5900 subname = get_subscription_name(object->objectId, missing_ok);
5901 if (subname)
5903 appendStringInfoString(&buffer,
5904 quote_identifier(subname));
5905 if (objname)
5906 *objname = list_make1(subname);
5908 break;
5911 case OCLASS_TRANSFORM:
5913 Relation transformDesc;
5914 HeapTuple tup;
5915 Form_pg_transform transform;
5916 char *transformLang;
5917 char *transformType;
5919 transformDesc = table_open(TransformRelationId, AccessShareLock);
5921 tup = get_catalog_object_by_oid(transformDesc,
5922 Anum_pg_transform_oid,
5923 object->objectId);
5925 if (!HeapTupleIsValid(tup))
5927 if (!missing_ok)
5928 elog(ERROR, "could not find tuple for transform %u",
5929 object->objectId);
5931 table_close(transformDesc, AccessShareLock);
5932 break;
5935 transform = (Form_pg_transform) GETSTRUCT(tup);
5937 transformType = format_type_be_qualified(transform->trftype);
5938 transformLang = get_language_name(transform->trflang, false);
5940 appendStringInfo(&buffer, "for %s on language %s",
5941 transformType,
5942 transformLang);
5943 if (objname)
5945 *objname = list_make1(transformType);
5946 *objargs = list_make1(pstrdup(transformLang));
5949 table_close(transformDesc, AccessShareLock);
5951 break;
5954 * There's intentionally no default: case here; we want the
5955 * compiler to warn if a new OCLASS hasn't been handled above.
5959 if (!missing_ok)
5962 * If a get_object_address() representation was requested, make sure
5963 * we are providing one. We don't check objargs, because many of the
5964 * cases above leave it as NIL.
5966 if (objname && *objname == NIL)
5967 elog(ERROR, "requested object address for unsupported object class %d: text result \"%s\"",
5968 (int) getObjectClass(object), buffer.data);
5970 else
5972 /* an empty buffer is equivalent to no object found */
5973 if (buffer.len == 0)
5975 Assert((objname == NULL || *objname == NIL) &&
5976 (objargs == NULL || *objargs == NIL));
5977 return NULL;
5981 return buffer.data;
5984 static void
5985 getOpFamilyIdentity(StringInfo buffer, Oid opfid, List **object,
5986 bool missing_ok)
5988 HeapTuple opfTup;
5989 Form_pg_opfamily opfForm;
5990 HeapTuple amTup;
5991 Form_pg_am amForm;
5992 char *schema;
5994 opfTup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfid));
5995 if (!HeapTupleIsValid(opfTup))
5997 if (!missing_ok)
5998 elog(ERROR, "cache lookup failed for opfamily %u", opfid);
5999 return;
6001 opfForm = (Form_pg_opfamily) GETSTRUCT(opfTup);
6003 amTup = SearchSysCache1(AMOID, ObjectIdGetDatum(opfForm->opfmethod));
6004 if (!HeapTupleIsValid(amTup))
6005 elog(ERROR, "cache lookup failed for access method %u",
6006 opfForm->opfmethod);
6007 amForm = (Form_pg_am) GETSTRUCT(amTup);
6009 schema = get_namespace_name_or_temp(opfForm->opfnamespace);
6010 appendStringInfo(buffer, "%s USING %s",
6011 quote_qualified_identifier(schema,
6012 NameStr(opfForm->opfname)),
6013 NameStr(amForm->amname));
6015 if (object)
6016 *object = list_make3(pstrdup(NameStr(amForm->amname)),
6017 pstrdup(schema),
6018 pstrdup(NameStr(opfForm->opfname)));
6020 ReleaseSysCache(amTup);
6021 ReleaseSysCache(opfTup);
6025 * Append the relation identity (quoted qualified name) to the given
6026 * StringInfo.
6028 static void
6029 getRelationIdentity(StringInfo buffer, Oid relid, List **object,
6030 bool missing_ok)
6032 HeapTuple relTup;
6033 Form_pg_class relForm;
6034 char *schema;
6036 relTup = SearchSysCache1(RELOID,
6037 ObjectIdGetDatum(relid));
6038 if (!HeapTupleIsValid(relTup))
6040 if (!missing_ok)
6041 elog(ERROR, "cache lookup failed for relation %u", relid);
6043 if (object)
6044 *object = NIL;
6045 return;
6047 relForm = (Form_pg_class) GETSTRUCT(relTup);
6049 schema = get_namespace_name_or_temp(relForm->relnamespace);
6050 appendStringInfoString(buffer,
6051 quote_qualified_identifier(schema,
6052 NameStr(relForm->relname)));
6053 if (object)
6054 *object = list_make2(schema, pstrdup(NameStr(relForm->relname)));
6056 ReleaseSysCache(relTup);
6060 * Auxiliary function to build a TEXT array out of a list of C-strings.
6062 ArrayType *
6063 strlist_to_textarray(List *list)
6065 ArrayType *arr;
6066 Datum *datums;
6067 bool *nulls;
6068 int j = 0;
6069 ListCell *cell;
6070 MemoryContext memcxt;
6071 MemoryContext oldcxt;
6072 int lb[1];
6074 /* Work in a temp context; easier than individually pfree'ing the Datums */
6075 memcxt = AllocSetContextCreate(CurrentMemoryContext,
6076 "strlist to array",
6077 ALLOCSET_DEFAULT_SIZES);
6078 oldcxt = MemoryContextSwitchTo(memcxt);
6080 datums = (Datum *) palloc(sizeof(Datum) * list_length(list));
6081 nulls = palloc(sizeof(bool) * list_length(list));
6083 foreach(cell, list)
6085 char *name = lfirst(cell);
6087 if (name)
6089 nulls[j] = false;
6090 datums[j++] = CStringGetTextDatum(name);
6092 else
6093 nulls[j] = true;
6096 MemoryContextSwitchTo(oldcxt);
6098 lb[0] = 1;
6099 arr = construct_md_array(datums, nulls, 1, &j,
6100 lb, TEXTOID, -1, false, TYPALIGN_INT);
6102 MemoryContextDelete(memcxt);
6104 return arr;
6108 * get_relkind_objtype
6110 * Return the object type for the relkind given by the caller.
6112 * If an unexpected relkind is passed, we say OBJECT_TABLE rather than
6113 * failing. That's because this is mostly used for generating error messages
6114 * for failed ACL checks on relations, and we'd rather produce a generic
6115 * message saying "table" than fail entirely.
6117 ObjectType
6118 get_relkind_objtype(char relkind)
6120 switch (relkind)
6122 case RELKIND_RELATION:
6123 case RELKIND_PARTITIONED_TABLE:
6124 return OBJECT_TABLE;
6125 case RELKIND_INDEX:
6126 case RELKIND_PARTITIONED_INDEX:
6127 return OBJECT_INDEX;
6128 case RELKIND_SEQUENCE:
6129 return OBJECT_SEQUENCE;
6130 case RELKIND_VIEW:
6131 return OBJECT_VIEW;
6132 case RELKIND_MATVIEW:
6133 return OBJECT_MATVIEW;
6134 case RELKIND_FOREIGN_TABLE:
6135 return OBJECT_FOREIGN_TABLE;
6136 case RELKIND_TOASTVALUE:
6137 return OBJECT_TABLE;
6138 default:
6139 /* Per above, don't raise an error */
6140 return OBJECT_TABLE;