1 /*-------------------------------------------------------------------------
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
11 * src/backend/catalog/objectaddress.c
13 *-------------------------------------------------------------------------
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"
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"
97 * This array provides a common part of system object structure; to help
98 * consolidate routines to handle various kind of object classes.
102 const char *class_descr
; /* string describing the catalog, for internal
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
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
[] =
126 AccessMethodRelationId
,
139 "access method operator",
140 AccessMethodOperatorRelationId
,
141 AccessMethodOperatorOidIndexId
,
153 "access method procedure",
154 AccessMethodProcedureRelationId
,
155 AccessMethodProcedureOidIndexId
,
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
,
196 ConstraintRelationId
,
197 ConstraintOidIndexId
,
200 Anum_pg_constraint_oid
,
201 Anum_pg_constraint_conname
,
202 Anum_pg_constraint_connamespace
,
210 ConversionRelationId
,
211 ConversionOidIndexId
,
214 Anum_pg_conversion_oid
,
215 Anum_pg_conversion_conname
,
216 Anum_pg_conversion_connamespace
,
217 Anum_pg_conversion_conowner
,
228 Anum_pg_database_oid
,
229 Anum_pg_database_datname
,
231 Anum_pg_database_datdba
,
232 Anum_pg_database_datacl
,
238 DefaultAclRelationId
,
239 DefaultAclOidIndexId
,
242 Anum_pg_default_acl_oid
,
256 Anum_pg_extension_oid
,
257 Anum_pg_extension_extname
,
258 InvalidAttrNumber
, /* extension doesn't belong to extnamespace */
259 Anum_pg_extension_extowner
,
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
,
273 Anum_pg_foreign_data_wrapper_fdwowner
,
274 Anum_pg_foreign_data_wrapper_fdwacl
,
280 ForeignServerRelationId
,
281 ForeignServerOidIndexId
,
284 Anum_pg_foreign_server_oid
,
285 Anum_pg_foreign_server_srvname
,
287 Anum_pg_foreign_server_srvowner
,
288 Anum_pg_foreign_server_srvacl
,
289 OBJECT_FOREIGN_SERVER
,
297 -1, /* PROCNAMEARGSNSP also takes argument types */
299 Anum_pg_proc_proname
,
300 Anum_pg_proc_pronamespace
,
301 Anum_pg_proc_proowner
,
312 Anum_pg_language_oid
,
313 Anum_pg_language_lanname
,
315 Anum_pg_language_lanowner
,
316 Anum_pg_language_lanacl
,
321 "large object metadata",
322 LargeObjectMetadataRelationId
,
323 LargeObjectMetadataOidIndexId
,
326 Anum_pg_largeobject_metadata_oid
,
329 Anum_pg_largeobject_metadata_lomowner
,
330 Anum_pg_largeobject_metadata_lomacl
,
336 OperatorClassRelationId
,
339 -1, /* CLAAMNAMENSP also takes opcmethod */
341 Anum_pg_opclass_opcname
,
342 Anum_pg_opclass_opcnamespace
,
343 Anum_pg_opclass_opcowner
,
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
,
364 OperatorFamilyRelationId
,
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
,
383 Anum_pg_authid_rolname
,
396 Anum_pg_auth_members_oid
,
399 Anum_pg_auth_members_grantor
,
411 Anum_pg_rewrite_rulename
,
424 Anum_pg_namespace_oid
,
425 Anum_pg_namespace_nspname
,
427 Anum_pg_namespace_nspowner
,
428 Anum_pg_namespace_nspacl
,
439 Anum_pg_class_relname
,
440 Anum_pg_class_relnamespace
,
441 Anum_pg_class_relowner
,
442 Anum_pg_class_relacl
,
448 TableSpaceRelationId
,
449 TablespaceOidIndexId
,
452 Anum_pg_tablespace_oid
,
453 Anum_pg_tablespace_spcname
,
455 Anum_pg_tablespace_spcowner
,
456 Anum_pg_tablespace_spcacl
,
466 Anum_pg_transform_oid
475 Anum_pg_trigger_tgname
,
489 Anum_pg_policy_polname
,
498 EventTriggerRelationId
,
499 EventTriggerOidIndexId
,
502 Anum_pg_event_trigger_oid
,
503 Anum_pg_event_trigger_evtname
,
505 Anum_pg_event_trigger_evtowner
,
507 OBJECT_EVENT_TRIGGER
,
511 "text search configuration",
516 Anum_pg_ts_config_oid
,
517 Anum_pg_ts_config_cfgname
,
518 Anum_pg_ts_config_cfgnamespace
,
519 Anum_pg_ts_config_cfgowner
,
521 OBJECT_TSCONFIGURATION
,
525 "text search dictionary",
526 TSDictionaryRelationId
,
527 TSDictionaryOidIndexId
,
531 Anum_pg_ts_dict_dictname
,
532 Anum_pg_ts_dict_dictnamespace
,
533 Anum_pg_ts_dict_dictowner
,
539 "text search parser",
544 Anum_pg_ts_parser_oid
,
545 Anum_pg_ts_parser_prsname
,
546 Anum_pg_ts_parser_prsnamespace
,
553 "text search template",
554 TSTemplateRelationId
,
555 TSTemplateOidIndexId
,
558 Anum_pg_ts_template_oid
,
559 Anum_pg_ts_template_tmplname
,
560 Anum_pg_ts_template_tmplnamespace
,
573 Anum_pg_type_typname
,
574 Anum_pg_type_typnamespace
,
575 Anum_pg_type_typowner
,
582 PublicationRelationId
,
583 PublicationObjectIndexId
,
586 Anum_pg_publication_oid
,
587 Anum_pg_publication_pubname
,
589 Anum_pg_publication_pubowner
,
596 SubscriptionRelationId
,
597 SubscriptionObjectIndexId
,
600 Anum_pg_subscription_oid
,
601 Anum_pg_subscription_subname
,
603 Anum_pg_subscription_subowner
,
609 "extended statistics",
610 StatisticExtRelationId
,
611 StatisticExtOidIndexId
,
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
,
624 UserMappingRelationId
,
625 UserMappingOidIndexId
,
628 Anum_pg_user_mapping_oid
,
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
655 /* OCLASS_CLASS, all kinds of relations */
657 "table", OBJECT_TABLE
660 "index", OBJECT_INDEX
663 "sequence", OBJECT_SEQUENCE
672 "materialized view", OBJECT_MATVIEW
678 "foreign table", OBJECT_FOREIGN_TABLE
681 "table column", OBJECT_COLUMN
687 "sequence column", -1
690 "toast table column", -1
696 "materialized view column", -1
699 "composite type column", -1
702 "foreign table column", OBJECT_COLUMN
706 "aggregate", OBJECT_AGGREGATE
709 "function", OBJECT_FUNCTION
712 "procedure", OBJECT_PROCEDURE
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
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
755 "operator class", OBJECT_OPCLASS
757 /* OCLASS_OPFAMILY */
759 "operator family", OBJECT_OPFAMILY
763 "access method", OBJECT_ACCESS_METHOD
767 "operator of access method", OBJECT_AMOP
771 "function of access method", OBJECT_AMPROC
779 "trigger", OBJECT_TRIGGER
783 "schema", OBJECT_SCHEMA
785 /* OCLASS_TSPARSER */
787 "text search parser", OBJECT_TSPARSER
791 "text search dictionary", OBJECT_TSDICTIONARY
793 /* OCLASS_TSTEMPLATE */
795 "text search template", OBJECT_TSTEMPLATE
797 /* OCLASS_TSCONFIG */
799 "text search configuration", OBJECT_TSCONFIGURATION
805 /* OCLASS_ROLE_MEMBERSHIP */
807 "role membership", -1 /* unmapped */
809 /* OCLASS_DATABASE */
811 "database", OBJECT_DATABASE
813 /* OCLASS_TBLSPACE */
815 "tablespace", OBJECT_TABLESPACE
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
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
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
=
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
,
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
,
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
,
904 static ObjectAddress
get_object_address_publication_rel(List
*object
,
907 static ObjectAddress
get_object_address_publication_schema(List
*object
,
909 static ObjectAddress
get_object_address_defacl(List
*object
,
911 static const ObjectPropertyType
*get_object_property_data(Oid class_id
);
913 static void getRelationDescription(StringInfo buffer
, Oid relid
,
915 static void getOpFamilyDescription(StringInfo buffer
, Oid opfid
,
917 static void getRelationTypeDescription(StringInfo buffer
, Oid relid
,
918 int32 objectSubId
, bool missing_ok
);
919 static void getProcedureTypeDescription(StringInfo buffer
, Oid procid
,
921 static void getConstraintTypeDescription(StringInfo buffer
, Oid constroid
,
923 static void getOpFamilyIdentity(StringInfo buffer
, Oid opfid
, List
**object
,
925 static void getRelationIdentity(StringInfo buffer
, Oid relid
, List
**object
,
929 * Translate an object name and arguments (as passed by the parser) to an
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
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.
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
;
968 /* Some kind of lock must be taken. */
969 Assert(lockmode
!= NoLock
);
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. */
984 case OBJECT_SEQUENCE
:
988 case OBJECT_FOREIGN_TABLE
:
990 get_relation_by_qualified_name(objtype
, castNode(List
, object
),
996 get_object_address_attribute(objtype
, castNode(List
, object
),
1000 case OBJECT_DEFAULT
:
1002 get_object_address_attrdef(objtype
, castNode(List
, object
),
1003 &relation
, lockmode
,
1007 case OBJECT_TRIGGER
:
1008 case OBJECT_TABCONSTRAINT
:
1010 address
= get_object_address_relobject(objtype
, castNode(List
, object
),
1011 &relation
, missing_ok
);
1013 case OBJECT_DOMCONSTRAINT
:
1016 ObjectAddress domaddr
;
1019 objlist
= castNode(List
, object
);
1020 domaddr
= get_object_address_type(OBJECT_DOMAIN
,
1021 linitial_node(TypeName
, objlist
),
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;
1031 case OBJECT_DATABASE
:
1032 case OBJECT_EXTENSION
:
1033 case OBJECT_TABLESPACE
:
1036 case OBJECT_LANGUAGE
:
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
);
1049 address
= get_object_address_type(objtype
, castNode(TypeName
, object
), missing_ok
);
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;
1059 case OBJECT_OPERATOR
:
1060 address
.classId
= OperatorRelationId
;
1061 address
.objectId
= LookupOperWithArgs(castNode(ObjectWithArgs
, object
), missing_ok
);
1062 address
.objectSubId
= 0;
1064 case OBJECT_COLLATION
:
1065 address
.classId
= CollationRelationId
;
1066 address
.objectId
= get_collation_oid(castNode(List
, object
), missing_ok
);
1067 address
.objectSubId
= 0;
1069 case OBJECT_CONVERSION
:
1070 address
.classId
= ConversionRelationId
;
1071 address
.objectId
= get_conversion_oid(castNode(List
, object
), missing_ok
);
1072 address
.objectSubId
= 0;
1074 case OBJECT_OPCLASS
:
1075 case OBJECT_OPFAMILY
:
1076 address
= get_object_address_opcf(objtype
, castNode(List
, object
), missing_ok
);
1080 address
= get_object_address_opf_member(objtype
, castNode(List
, object
), missing_ok
);
1082 case OBJECT_LARGEOBJECT
:
1083 address
.classId
= LargeObjectRelationId
;
1084 address
.objectId
= oidparse(object
);
1085 address
.objectSubId
= 0;
1086 if (!LargeObjectExists(address
.objectId
))
1090 (errcode(ERRCODE_UNDEFINED_OBJECT
),
1091 errmsg("large object %u does not exist",
1092 address
.objectId
)));
1097 TypeName
*sourcetype
= linitial_node(TypeName
, castNode(List
, object
));
1098 TypeName
*targettype
= lsecond_node(TypeName
, castNode(List
, object
));
1102 sourcetypeid
= LookupTypeNameOid(NULL
, sourcetype
, missing_ok
);
1103 targettypeid
= LookupTypeNameOid(NULL
, targettype
, missing_ok
);
1104 address
.classId
= CastRelationId
;
1106 get_cast_oid(sourcetypeid
, targettypeid
, missing_ok
);
1107 address
.objectSubId
= 0;
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
;
1119 get_transform_oid(type_id
, lang_id
, missing_ok
);
1120 address
.objectSubId
= 0;
1123 case OBJECT_TSPARSER
:
1124 address
.classId
= TSParserRelationId
;
1125 address
.objectId
= get_ts_parser_oid(castNode(List
, object
), missing_ok
);
1126 address
.objectSubId
= 0;
1128 case OBJECT_TSDICTIONARY
:
1129 address
.classId
= TSDictionaryRelationId
;
1130 address
.objectId
= get_ts_dict_oid(castNode(List
, object
), missing_ok
);
1131 address
.objectSubId
= 0;
1133 case OBJECT_TSTEMPLATE
:
1134 address
.classId
= TSTemplateRelationId
;
1135 address
.objectId
= get_ts_template_oid(castNode(List
, object
), missing_ok
);
1136 address
.objectSubId
= 0;
1138 case OBJECT_TSCONFIGURATION
:
1139 address
.classId
= TSConfigRelationId
;
1140 address
.objectId
= get_ts_config_oid(castNode(List
, object
), missing_ok
);
1141 address
.objectSubId
= 0;
1143 case OBJECT_USER_MAPPING
:
1144 address
= get_object_address_usermapping(castNode(List
, object
),
1147 case OBJECT_PUBLICATION_NAMESPACE
:
1148 address
= get_object_address_publication_schema(castNode(List
, object
),
1151 case OBJECT_PUBLICATION_REL
:
1152 address
= get_object_address_publication_rel(castNode(List
, object
),
1157 address
= get_object_address_defacl(castNode(List
, object
),
1160 case OBJECT_STATISTIC_EXT
:
1161 address
.classId
= StatisticExtRelationId
;
1162 address
.objectId
= get_statistics_object_oid(castNode(List
, object
),
1164 address
.objectSubId
= 0;
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
))
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
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
)
1194 if (old_address
.classId
!= RelationRelationId
)
1196 if (IsSharedRelation(old_address
.classId
))
1197 UnlockSharedObject(old_address
.classId
,
1198 old_address
.objectId
,
1201 UnlockDatabaseObject(old_address
.classId
,
1202 old_address
.objectId
,
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,
1217 LockDatabaseObject(address
.classId
, address
.objectId
, 0,
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
)
1243 old_address
= address
;
1246 /* Return the object address and the relation. */
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.
1259 get_object_address_rv(ObjectType objtype
, RangeVar
*rel
, List
*object
,
1260 Relation
*relp
, LOCKMODE lockmode
,
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
1280 static ObjectAddress
1281 get_object_address_unqualified(ObjectType objtype
,
1282 String
*strval
, bool missing_ok
)
1285 ObjectAddress address
;
1287 name
= strVal(strval
);
1289 /* Translate name to OID. */
1292 case OBJECT_ACCESS_METHOD
:
1293 address
.classId
= AccessMethodRelationId
;
1294 address
.objectId
= get_am_oid(name
, missing_ok
);
1295 address
.objectSubId
= 0;
1297 case OBJECT_DATABASE
:
1298 address
.classId
= DatabaseRelationId
;
1299 address
.objectId
= get_database_oid(name
, missing_ok
);
1300 address
.objectSubId
= 0;
1302 case OBJECT_EXTENSION
:
1303 address
.classId
= ExtensionRelationId
;
1304 address
.objectId
= get_extension_oid(name
, missing_ok
);
1305 address
.objectSubId
= 0;
1307 case OBJECT_TABLESPACE
:
1308 address
.classId
= TableSpaceRelationId
;
1309 address
.objectId
= get_tablespace_oid(name
, missing_ok
);
1310 address
.objectSubId
= 0;
1313 address
.classId
= AuthIdRelationId
;
1314 address
.objectId
= get_role_oid(name
, missing_ok
);
1315 address
.objectSubId
= 0;
1318 address
.classId
= NamespaceRelationId
;
1319 address
.objectId
= get_namespace_oid(name
, missing_ok
);
1320 address
.objectSubId
= 0;
1322 case OBJECT_LANGUAGE
:
1323 address
.classId
= LanguageRelationId
;
1324 address
.objectId
= get_language_oid(name
, missing_ok
);
1325 address
.objectSubId
= 0;
1328 address
.classId
= ForeignDataWrapperRelationId
;
1329 address
.objectId
= get_foreign_data_wrapper_oid(name
, missing_ok
);
1330 address
.objectSubId
= 0;
1332 case OBJECT_FOREIGN_SERVER
:
1333 address
.classId
= ForeignServerRelationId
;
1334 address
.objectId
= get_foreign_server_oid(name
, missing_ok
);
1335 address
.objectSubId
= 0;
1337 case OBJECT_EVENT_TRIGGER
:
1338 address
.classId
= EventTriggerRelationId
;
1339 address
.objectId
= get_event_trigger_oid(name
, missing_ok
);
1340 address
.objectSubId
= 0;
1342 case OBJECT_PARAMETER_ACL
:
1343 address
.classId
= ParameterAclRelationId
;
1344 address
.objectId
= ParameterAclLookup(name
, missing_ok
);
1345 address
.objectSubId
= 0;
1347 case OBJECT_PUBLICATION
:
1348 address
.classId
= PublicationRelationId
;
1349 address
.objectId
= get_publication_oid(name
, missing_ok
);
1350 address
.objectSubId
= 0;
1352 case OBJECT_SUBSCRIPTION
:
1353 address
.classId
= SubscriptionRelationId
;
1354 address
.objectId
= get_subscription_oid(name
, missing_ok
);
1355 address
.objectSubId
= 0;
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;
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
,
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
);
1391 if (relation
->rd_rel
->relkind
!= RELKIND_INDEX
&&
1392 relation
->rd_rel
->relkind
!= RELKIND_PARTITIONED_INDEX
)
1394 (errcode(ERRCODE_WRONG_OBJECT_TYPE
),
1395 errmsg("\"%s\" is not an index",
1396 RelationGetRelationName(relation
))));
1398 case OBJECT_SEQUENCE
:
1399 if (relation
->rd_rel
->relkind
!= RELKIND_SEQUENCE
)
1401 (errcode(ERRCODE_WRONG_OBJECT_TYPE
),
1402 errmsg("\"%s\" is not a sequence",
1403 RelationGetRelationName(relation
))));
1406 if (relation
->rd_rel
->relkind
!= RELKIND_RELATION
&&
1407 relation
->rd_rel
->relkind
!= RELKIND_PARTITIONED_TABLE
)
1409 (errcode(ERRCODE_WRONG_OBJECT_TYPE
),
1410 errmsg("\"%s\" is not a table",
1411 RelationGetRelationName(relation
))));
1414 if (relation
->rd_rel
->relkind
!= RELKIND_VIEW
)
1416 (errcode(ERRCODE_WRONG_OBJECT_TYPE
),
1417 errmsg("\"%s\" is not a view",
1418 RelationGetRelationName(relation
))));
1420 case OBJECT_MATVIEW
:
1421 if (relation
->rd_rel
->relkind
!= RELKIND_MATVIEW
)
1423 (errcode(ERRCODE_WRONG_OBJECT_TYPE
),
1424 errmsg("\"%s\" is not a materialized view",
1425 RelationGetRelationName(relation
))));
1427 case OBJECT_FOREIGN_TABLE
:
1428 if (relation
->rd_rel
->relkind
!= RELKIND_FOREIGN_TABLE
)
1430 (errcode(ERRCODE_WRONG_OBJECT_TYPE
),
1431 errmsg("\"%s\" is not a foreign table",
1432 RelationGetRelationName(relation
))));
1435 elog(ERROR
, "unrecognized object type: %d", (int) objtype
);
1440 address
.objectId
= RelationGetRelid(relation
);
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
;
1460 const char *depname
;
1464 /* Extract name of dependent object. */
1465 depname
= strVal(llast(object
));
1467 /* Separate relation name from dependent object name. */
1468 nnames
= list_length(object
);
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
),
1480 reloid
= relation
? RelationGetRelid(relation
) : InvalidOid
;
1485 address
.classId
= RewriteRelationId
;
1486 address
.objectId
= relation
?
1487 get_rewrite_oid(reloid
, depname
, missing_ok
) : InvalidOid
;
1488 address
.objectSubId
= 0;
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;
1496 case OBJECT_TABCONSTRAINT
:
1497 address
.classId
= ConstraintRelationId
;
1498 address
.objectId
= relation
?
1499 get_relation_constraint_oid(reloid
, depname
, missing_ok
) :
1501 address
.objectSubId
= 0;
1504 address
.classId
= PolicyRelationId
;
1505 address
.objectId
= relation
?
1506 get_relation_policy_oid(reloid
, depname
, missing_ok
) :
1508 address
.objectSubId
= 0;
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 */
1530 * Find the ObjectAddress for an attribute.
1532 static ObjectAddress
1533 get_object_address_attribute(ObjectType objtype
, List
*object
,
1534 Relation
*relp
, LOCKMODE lockmode
,
1537 ObjectAddress address
;
1541 const char *attname
;
1544 /* Extract relation name and open relation. */
1545 if (list_length(object
) < 2)
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
)
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
);
1572 address
.classId
= RelationRelationId
;
1573 address
.objectId
= reloid
;
1574 address
.objectSubId
= attnum
;
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
,
1588 ObjectAddress address
;
1592 const char *attname
;
1597 /* Extract relation name and open relation. */
1598 if (list_length(object
) < 2)
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
))
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
);
1630 address
.classId
= AttrDefaultRelationId
;
1631 address
.objectId
= defoid
;
1632 address
.objectSubId
= 0;
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
;
1647 address
.classId
= TypeRelationId
;
1648 address
.objectId
= InvalidOid
;
1649 address
.objectSubId
= 0;
1651 tup
= LookupTypeName(NULL
, typename
, NULL
, missing_ok
);
1652 if (!HeapTupleIsValid(tup
))
1656 (errcode(ERRCODE_UNDEFINED_OBJECT
),
1657 errmsg("type \"%s\" does not exist",
1658 TypeNameToString(typename
))));
1661 address
.objectId
= typeTypeId(tup
);
1663 if (objtype
== OBJECT_DOMAIN
)
1665 if (((Form_pg_type
) GETSTRUCT(tup
))->typtype
!= TYPTYPE_DOMAIN
)
1667 (errcode(ERRCODE_WRONG_OBJECT_TYPE
),
1668 errmsg("\"%s\" is not a domain",
1669 TypeNameToString(typename
))));
1672 ReleaseSysCache(tup
);
1678 * Find the ObjectAddress for an opclass or opfamily.
1680 static ObjectAddress
1681 get_object_address_opcf(ObjectType objtype
, List
*object
, bool missing_ok
)
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);
1692 case OBJECT_OPCLASS
:
1693 address
.classId
= OperatorClassRelationId
;
1694 address
.objectId
= get_opclass_oid(amoid
, object
, missing_ok
);
1695 address
.objectSubId
= 0;
1697 case OBJECT_OPFAMILY
:
1698 address
.classId
= OperatorFamilyRelationId
;
1699 address
.objectId
= get_opfamily_oid(amoid
, object
, missing_ok
);
1700 address
.objectSubId
= 0;
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;
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
;
1726 TypeName
*typenames
[2];
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
;
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
;
1763 ObjectAddressSet(address
, AccessMethodOperatorRelationId
,
1766 tp
= SearchSysCache4(AMOPSTRATEGY
,
1767 ObjectIdGetDatum(famaddr
.objectId
),
1768 ObjectIdGetDatum(typeoids
[0]),
1769 ObjectIdGetDatum(typeoids
[1]),
1770 Int16GetDatum(membernum
));
1771 if (!HeapTupleIsValid(tp
))
1775 (errcode(ERRCODE_UNDEFINED_OBJECT
),
1776 errmsg("operator %d (%s, %s) of %s does not exist",
1778 TypeNameToString(typenames
[0]),
1779 TypeNameToString(typenames
[1]),
1780 getObjectDescription(&famaddr
, false))));
1784 address
.objectId
= ((Form_pg_amop
) GETSTRUCT(tp
))->oid
;
1785 ReleaseSysCache(tp
);
1794 ObjectAddressSet(address
, AccessMethodProcedureRelationId
,
1797 tp
= SearchSysCache4(AMPROCNUM
,
1798 ObjectIdGetDatum(famaddr
.objectId
),
1799 ObjectIdGetDatum(typeoids
[0]),
1800 ObjectIdGetDatum(typeoids
[1]),
1801 Int16GetDatum(membernum
));
1802 if (!HeapTupleIsValid(tp
))
1806 (errcode(ERRCODE_UNDEFINED_OBJECT
),
1807 errmsg("function %d (%s, %s) of %s does not exist",
1809 TypeNameToString(typenames
[0]),
1810 TypeNameToString(typenames
[1]),
1811 getObjectDescription(&famaddr
, false))));
1815 address
.objectId
= ((Form_pg_amproc
) GETSTRUCT(tp
))->oid
;
1816 ReleaseSysCache(tp
);
1821 elog(ERROR
, "unrecognized object type: %d", (int) objtype
);
1828 * Find the ObjectAddress for a user mapping.
1830 static ObjectAddress
1831 get_object_address_usermapping(List
*object
, bool missing_ok
)
1833 ObjectAddress address
;
1837 ForeignServer
*server
;
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
;
1851 tp
= SearchSysCache1(AUTHNAME
,
1852 CStringGetDatum(username
));
1853 if (!HeapTupleIsValid(tp
))
1857 (errcode(ERRCODE_UNDEFINED_OBJECT
),
1858 errmsg("user mapping for user \"%s\" on server \"%s\" does not exist",
1859 username
, servername
)));
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);
1872 (errcode(ERRCODE_UNDEFINED_OBJECT
),
1873 errmsg("server \"%s\" does not exist", servername
)));
1876 tp
= SearchSysCache2(USERMAPPINGUSERSERVER
,
1877 ObjectIdGetDatum(userid
),
1878 ObjectIdGetDatum(server
->serverid
));
1879 if (!HeapTupleIsValid(tp
))
1883 (errcode(ERRCODE_UNDEFINED_OBJECT
),
1884 errmsg("user mapping for user \"%s\" on server \"%s\" does not exist",
1885 username
, servername
)));
1889 address
.objectId
= ((Form_pg_user_mapping
) GETSTRUCT(tp
))->oid
;
1891 ReleaseSysCache(tp
);
1897 * Find the ObjectAddress for a publication relation. The first element of
1898 * the object parameter is the relation name, the second is the
1901 static ObjectAddress
1902 get_object_address_publication_rel(List
*object
,
1903 Relation
*relp
, bool missing_ok
)
1905 ObjectAddress address
;
1911 ObjectAddressSet(address
, PublicationRelRelationId
, InvalidOid
);
1913 relname
= linitial(object
);
1914 relation
= relation_openrv_extended(makeRangeVarFromNameList(relname
),
1915 AccessShareLock
, missing_ok
);
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
);
1926 relation_close(relation
, AccessShareLock
);
1930 /* Find the publication relation mapping in syscache. */
1932 GetSysCacheOid2(PUBLICATIONRELMAP
, Anum_pg_publication_rel_oid
,
1933 ObjectIdGetDatum(RelationGetRelid(relation
)),
1934 ObjectIdGetDatum(pub
->oid
));
1935 if (!OidIsValid(address
.objectId
))
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
);
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
;
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
))
1973 /* Now look up the pg_publication tuple */
1974 pub
= GetPublicationByName(pubname
, missing_ok
);
1978 /* Find the publication schema mapping in syscache */
1980 GetSysCacheOid2(PUBLICATIONNAMESPACEMAP
,
1981 Anum_pg_publication_namespace_oid
,
1982 ObjectIdGetDatum(schemaid
),
1983 ObjectIdGetDatum(pub
->oid
));
1984 if (!OidIsValid(address
.objectId
) && !missing_ok
)
1986 (errcode(ERRCODE_UNDEFINED_OBJECT
),
1987 errmsg("publication schema \"%s\" in publication \"%s\" does not exist",
1988 schemaname
, pubname
)));
1994 * Find the ObjectAddress for a default ACL.
1996 static ObjectAddress
1997 get_object_address_defacl(List
*object
, bool missing_ok
)
2006 ObjectAddress address
;
2008 ObjectAddressSet(address
, DefaultAclRelationId
, InvalidOid
);
2011 * First figure out the textual attributes so that they can be used for
2014 username
= strVal(lsecond(object
));
2015 if (list_length(object
) >= 3)
2016 schema
= (char *) strVal(lthird(object
));
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];
2027 case DEFACLOBJ_RELATION
:
2028 objtype_str
= "tables";
2030 case DEFACLOBJ_SEQUENCE
:
2031 objtype_str
= "sequences";
2033 case DEFACLOBJ_FUNCTION
:
2034 objtype_str
= "functions";
2036 case DEFACLOBJ_TYPE
:
2037 objtype_str
= "types";
2039 case DEFACLOBJ_NAMESPACE
:
2040 objtype_str
= "schemas";
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\".",
2051 DEFACLOBJ_NAMESPACE
)));
2055 * Look up user ID. Behave as "default ACL not found" if the user doesn't
2058 tp
= SearchSysCache1(AUTHNAME
,
2059 CStringGetDatum(username
));
2060 if (!HeapTupleIsValid(tp
))
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".
2071 schemaid
= get_namespace_oid(schema
, true);
2072 if (schemaid
== InvalidOid
)
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
))
2086 address
.objectId
= ((Form_pg_default_acl
) GETSTRUCT(tp
))->oid
;
2087 ReleaseSysCache(tp
);
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
)));
2101 (errcode(ERRCODE_UNDEFINED_OBJECT
),
2102 errmsg("default ACL for user \"%s\" on %s does not exist",
2103 username
, objtype_str
)));
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.
2113 textarray_to_strvaluelist(ArrayType
*arr
)
2121 deconstruct_array_builtin(arr
, TEXTOID
, &elems
, &nulls
, &nelems
);
2123 for (i
= 0; i
< nelems
; i
++)
2127 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
2128 errmsg("name or argument lists may not contain nulls")));
2129 list
= lappend(list
, makeString(TextDatumGetCString(elems
[i
])));
2136 * SQL-callable version of get_object_address
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);
2147 TypeName
*typename
= NULL
;
2149 Node
*objnode
= NULL
;
2157 /* Decode object type, raise error if unknown */
2158 itype
= read_objtype_from_string(ttype
);
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
2170 if (type
== OBJECT_TYPE
|| type
== OBJECT_DOMAIN
|| type
== OBJECT_CAST
||
2171 type
== OBJECT_TRANSFORM
|| type
== OBJECT_DOMCONSTRAINT
)
2177 deconstruct_array_builtin(namearr
, TEXTOID
, &elems
, &nulls
, &nelems
);
2180 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
2181 errmsg("name list length must be exactly %d", 1)));
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
)
2194 deconstruct_array_builtin(namearr
, TEXTOID
, &elems
, &nulls
, &nelems
);
2197 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
2198 errmsg("name list length must be exactly %d", 1)));
2201 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
2202 errmsg("large object OID may not be null")));
2203 objnode
= (Node
*) makeFloat(TextDatumGetCString(elems
[0]));
2207 name
= textarray_to_strvaluelist(namearr
);
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 */
2232 deconstruct_array_builtin(argsarr
, TEXTOID
, &elems
, &nulls
, &nelems
);
2235 for (i
= 0; i
< nelems
; i
++)
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
])));
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.
2257 case OBJECT_PUBLICATION_NAMESPACE
:
2258 case OBJECT_USER_MAPPING
:
2259 if (list_length(name
) != 1)
2261 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
2262 errmsg("name list length must be exactly %d", 1)));
2263 /* fall through to check args length */
2265 case OBJECT_DOMCONSTRAINT
:
2267 case OBJECT_PUBLICATION_REL
:
2269 case OBJECT_TRANSFORM
:
2270 if (list_length(args
) != 1)
2272 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
2273 errmsg("argument list length must be exactly %d", 1)));
2275 case OBJECT_OPFAMILY
:
2276 case OBJECT_OPCLASS
:
2277 if (list_length(name
) < 2)
2279 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
2280 errmsg("name list length must be at least %d", 2)));
2284 if (list_length(name
) < 3)
2286 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
2287 errmsg("name list length must be at least %d", 3)));
2288 /* fall through to check args length */
2290 case OBJECT_OPERATOR
:
2291 if (list_length(args
) != 2)
2293 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
2294 errmsg("argument list length must be exactly %d", 2)));
2301 * Now build the Node type that get_object_address() expects for the given
2307 case OBJECT_SEQUENCE
:
2309 case OBJECT_MATVIEW
:
2311 case OBJECT_FOREIGN_TABLE
:
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
:
2324 case OBJECT_TRIGGER
:
2325 case OBJECT_TABCONSTRAINT
:
2326 case OBJECT_OPCLASS
:
2327 case OBJECT_OPFAMILY
:
2328 objnode
= (Node
*) name
;
2330 case OBJECT_ACCESS_METHOD
:
2331 case OBJECT_DATABASE
:
2332 case OBJECT_EVENT_TRIGGER
:
2333 case OBJECT_EXTENSION
:
2335 case OBJECT_FOREIGN_SERVER
:
2336 case OBJECT_LANGUAGE
:
2337 case OBJECT_PARAMETER_ACL
:
2338 case OBJECT_PUBLICATION
:
2341 case OBJECT_SUBSCRIPTION
:
2342 case OBJECT_TABLESPACE
:
2343 if (list_length(name
) != 1)
2345 (errcode(ERRCODE_INVALID_PARAMETER_VALUE
),
2346 errmsg("name list length must be exactly %d", 1)));
2347 objnode
= linitial(name
);
2351 objnode
= (Node
*) typename
;
2354 case OBJECT_DOMCONSTRAINT
:
2355 case OBJECT_TRANSFORM
:
2356 objnode
= (Node
*) list_make2(typename
, linitial(args
));
2358 case OBJECT_PUBLICATION_REL
:
2359 objnode
= (Node
*) list_make2(name
, linitial(args
));
2361 case OBJECT_PUBLICATION_NAMESPACE
:
2362 case OBJECT_USER_MAPPING
:
2363 objnode
= (Node
*) list_make2(linitial(name
), linitial(args
));
2366 objnode
= (Node
*) lcons(linitial(args
), name
);
2370 objnode
= (Node
*) list_make2(name
, args
);
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
;
2385 case OBJECT_LARGEOBJECT
:
2386 /* already handled above */
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 */
2399 relation_close(relation
, AccessShareLock
);
2401 tupdesc
= CreateTemplateTupleDesc(3);
2402 TupleDescInitEntry(tupdesc
, (AttrNumber
) 1, "classid",
2404 TupleDescInitEntry(tupdesc
, (AttrNumber
) 2, "objid",
2406 TupleDescInitEntry(tupdesc
, (AttrNumber
) 3, "objsubid",
2408 tupdesc
= BlessTupleDesc(tupdesc
);
2410 values
[0] = ObjectIdGetDatum(addr
.classId
);
2411 values
[1] = ObjectIdGetDatum(addr
.objectId
);
2412 values
[2] = Int32GetDatum(addr
.objectSubId
);
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.
2426 check_object_ownership(Oid roleid
, ObjectType objtype
, ObjectAddress address
,
2427 Node
*object
, Relation relation
)
2432 case OBJECT_SEQUENCE
:
2435 case OBJECT_MATVIEW
:
2436 case OBJECT_FOREIGN_TABLE
:
2439 case OBJECT_TRIGGER
:
2441 case OBJECT_TABCONSTRAINT
:
2442 if (!object_ownercheck(RelationRelationId
, RelationGetRelid(relation
), roleid
))
2443 aclcheck_error(ACLCHECK_NOT_OWNER
, objtype
,
2444 RelationGetRelationName(relation
));
2448 case OBJECT_ATTRIBUTE
:
2449 if (!object_ownercheck(address
.classId
, address
.objectId
, roleid
))
2450 aclcheck_error_type(ACLCHECK_NOT_OWNER
, address
.objectId
);
2452 case OBJECT_DOMCONSTRAINT
:
2457 tuple
= SearchSysCache1(CONSTROID
,
2458 ObjectIdGetDatum(address
.objectId
));
2459 if (!HeapTupleIsValid(tuple
))
2460 elog(ERROR
, "constraint with OID %u does not exist",
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
);
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
));
2484 case OBJECT_DATABASE
:
2485 case OBJECT_EVENT_TRIGGER
:
2486 case OBJECT_EXTENSION
:
2488 case OBJECT_FOREIGN_SERVER
:
2489 case OBJECT_LANGUAGE
:
2490 case OBJECT_PUBLICATION
:
2492 case OBJECT_SUBSCRIPTION
:
2493 case OBJECT_TABLESPACE
:
2494 if (!object_ownercheck(address
.classId
, address
.objectId
, roleid
))
2495 aclcheck_error(ACLCHECK_NOT_OWNER
, objtype
,
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
)));
2509 case OBJECT_LARGEOBJECT
:
2510 if (!lo_compat_privileges
&&
2511 !object_ownercheck(address
.classId
, address
.objectId
, roleid
))
2513 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
2514 errmsg("must be owner of large object %u",
2515 address
.objectId
)));
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
))
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
))));
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);
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
))
2553 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
2554 errmsg("must be superuser")));
2558 if (!has_createrole_privilege(roleid
))
2560 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
2561 errmsg("must have CREATEROLE privilege")));
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
))
2571 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE
),
2572 errmsg("must be superuser")));
2575 elog(ERROR
, "unrecognized object type: %d",
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
)
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
)
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
,
2611 property
->attnum_namespace
,
2614 ReleaseSysCache(tuple
);
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
)
2630 for (i
= 0; i
< lengthof(ObjectTypeMap
); i
++)
2632 if (strcmp(ObjectTypeMap
[i
].tm_name
, objtype
) == 0)
2633 return ObjectTypeMap
[i
].tm_type
;
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
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
;
2678 get_object_attnum_oid(Oid class_id
)
2680 const ObjectPropertyType
*prop
= get_object_property_data(class_id
);
2682 return prop
->attnum_oid
;
2686 get_object_attnum_name(Oid class_id
)
2688 const ObjectPropertyType
*prop
= get_object_property_data(class_id
);
2690 return prop
->attnum_name
;
2694 get_object_attnum_namespace(Oid class_id
)
2696 const ObjectPropertyType
*prop
= get_object_property_data(class_id
);
2698 return prop
->attnum_namespace
;
2702 get_object_attnum_owner(Oid class_id
)
2704 const ObjectPropertyType
*prop
= get_object_property_data(class_id
);
2706 return prop
->attnum_owner
;
2710 get_object_attnum_acl(Oid class_id
)
2712 const ObjectPropertyType
*prop
= get_object_property_data(class_id
);
2714 return prop
->attnum_acl
;
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.
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
2736 return get_relkind_objtype(get_rel_relkind(object_id
));
2739 return prop
->objtype
;
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.
2755 is_objectclass_supported(Oid class_id
)
2759 for (index
= 0; index
< lengthof(ObjectProperty
); index
++)
2761 if (ObjectProperty
[index
].class_oid
== class_id
)
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
;
2778 * A shortcut to speed up multiple consecutive lookups of a particular
2781 if (prop_last
&& prop_last
->class_oid
== class_id
)
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
];
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.
2807 get_catalog_object_by_oid(Relation catalog
, AttrNumber oidcol
, Oid objectId
)
2810 Oid classId
= RelationGetRelid(catalog
);
2811 int oidCacheId
= get_object_catcache_oid(classId
);
2815 tuple
= SearchSysCacheCopy1(oidCacheId
, ObjectIdGetDatum(objectId
));
2816 if (!HeapTupleIsValid(tuple
)) /* should not happen */
2821 Oid oidIndexId
= get_object_oid_index(classId
);
2825 Assert(OidIsValid(oidIndexId
));
2829 BTEqualStrategyNumber
, F_OIDEQ
,
2830 ObjectIdGetDatum(objectId
));
2832 scan
= systable_beginscan(catalog
, oidIndexId
, true,
2834 tuple
= systable_getnext(scan
);
2835 if (!HeapTupleIsValid(tuple
))
2837 systable_endscan(scan
);
2840 tuple
= heap_copytuple(tuple
);
2842 systable_endscan(scan
);
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
2856 getPublicationSchemaInfo(const ObjectAddress
*object
, bool missing_ok
,
2857 char **pubname
, char **nspname
)
2860 Form_pg_publication_namespace pnform
;
2862 tup
= SearchSysCache1(PUBLICATIONNAMESPACE
,
2863 ObjectIdGetDatum(object
->objectId
));
2864 if (!HeapTupleIsValid(tup
))
2867 elog(ERROR
, "cache lookup failed for publication schema %u",
2872 pnform
= (Form_pg_publication_namespace
) GETSTRUCT(tup
);
2873 *pubname
= get_publication_name(pnform
->pnpubid
, missing_ok
);
2876 ReleaseSysCache(tup
);
2880 *nspname
= get_namespace_name(pnform
->pnnspid
);
2883 Oid schemaid
= pnform
->pnnspid
;
2886 ReleaseSysCache(tup
);
2888 elog(ERROR
, "cache lookup failed for schema %u",
2893 ReleaseSysCache(tup
);
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.
2904 getObjectDescription(const ObjectAddress
*object
, bool missing_ok
)
2906 StringInfoData buffer
;
2908 initStringInfo(&buffer
);
2910 switch (getObjectClass(object
))
2913 if (object
->objectSubId
== 0)
2914 getRelationDescription(&buffer
, object
->objectId
, missing_ok
);
2917 /* column, not whole relation */
2919 char *attname
= get_attname(object
->objectId
,
2920 object
->objectSubId
,
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"),
2937 bits16 flags
= FORMAT_PROC_INVALID_AS_NULL
;
2938 char *proname
= format_procedure_extended(object
->objectId
,
2941 if (proname
== NULL
)
2944 appendStringInfo(&buffer
, _("function %s"), proname
);
2950 bits16 flags
= FORMAT_TYPE_INVALID_AS_NULL
;
2951 char *typname
= format_type_extended(object
->objectId
, -1,
2954 if (typname
== NULL
)
2957 appendStringInfo(&buffer
, _("type %s"), typname
);
2964 ScanKeyData skey
[1];
2967 Form_pg_cast castForm
;
2969 castDesc
= table_open(CastRelationId
, AccessShareLock
);
2971 ScanKeyInit(&skey
[0],
2973 BTEqualStrategyNumber
, F_OIDEQ
,
2974 ObjectIdGetDatum(object
->objectId
));
2976 rcscan
= systable_beginscan(castDesc
, CastOidIndexId
, true,
2979 tup
= systable_getnext(rcscan
);
2981 if (!HeapTupleIsValid(tup
))
2984 elog(ERROR
, "could not find tuple for cast %u",
2987 systable_endscan(rcscan
);
2988 table_close(castDesc
, AccessShareLock
);
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
);
3003 case OCLASS_COLLATION
:
3006 Form_pg_collation coll
;
3009 collTup
= SearchSysCache1(COLLOID
,
3010 ObjectIdGetDatum(object
->objectId
));
3011 if (!HeapTupleIsValid(collTup
))
3014 elog(ERROR
, "cache lookup failed for collation %u",
3019 coll
= (Form_pg_collation
) GETSTRUCT(collTup
);
3021 /* Qualify the name if not visible in search path */
3022 if (CollationIsVisible(object
->objectId
))
3025 nspname
= get_namespace_name(coll
->collnamespace
);
3027 appendStringInfo(&buffer
, _("collation %s"),
3028 quote_qualified_identifier(nspname
,
3029 NameStr(coll
->collname
)));
3030 ReleaseSysCache(collTup
);
3034 case OCLASS_CONSTRAINT
:
3037 Form_pg_constraint con
;
3039 conTup
= SearchSysCache1(CONSTROID
,
3040 ObjectIdGetDatum(object
->objectId
));
3041 if (!HeapTupleIsValid(conTup
))
3044 elog(ERROR
, "cache lookup failed for constraint %u",
3049 con
= (Form_pg_constraint
) GETSTRUCT(conTup
);
3051 if (OidIsValid(con
->conrelid
))
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
);
3064 appendStringInfo(&buffer
, _("constraint %s"),
3065 NameStr(con
->conname
));
3068 ReleaseSysCache(conTup
);
3072 case OCLASS_CONVERSION
:
3075 Form_pg_conversion conv
;
3078 conTup
= SearchSysCache1(CONVOID
,
3079 ObjectIdGetDatum(object
->objectId
));
3080 if (!HeapTupleIsValid(conTup
))
3083 elog(ERROR
, "cache lookup failed for conversion %u",
3088 conv
= (Form_pg_conversion
) GETSTRUCT(conTup
);
3090 /* Qualify the name if not visible in search path */
3091 if (ConversionIsVisible(object
->objectId
))
3094 nspname
= get_namespace_name(conv
->connamespace
);
3096 appendStringInfo(&buffer
, _("conversion %s"),
3097 quote_qualified_identifier(nspname
,
3098 NameStr(conv
->conname
)));
3099 ReleaseSysCache(conTup
);
3103 case OCLASS_DEFAULT
:
3105 ObjectAddress colobject
;
3107 colobject
= GetAttrDefaultColumnAddress(object
->objectId
);
3109 if (!OidIsValid(colobject
.objectId
))
3112 elog(ERROR
, "could not find tuple for attrdef %u",
3117 /* translator: %s is typically "column %s of table %s" */
3118 appendStringInfo(&buffer
, _("default value for %s"),
3119 getObjectDescription(&colobject
, false));
3123 case OCLASS_LANGUAGE
:
3125 char *langname
= get_language_name(object
->objectId
,
3129 appendStringInfo(&buffer
, _("language %s"),
3130 get_language_name(object
->objectId
, false));
3134 case OCLASS_LARGEOBJECT
:
3135 if (!LargeObjectExists(object
->objectId
))
3137 appendStringInfo(&buffer
, _("large object %u"),
3141 case OCLASS_OPERATOR
:
3143 bits16 flags
= FORMAT_OPERATOR_INVALID_AS_NULL
;
3144 char *oprname
= format_operator_extended(object
->objectId
,
3147 if (oprname
== NULL
)
3150 appendStringInfo(&buffer
, _("operator %s"), oprname
);
3154 case OCLASS_OPCLASS
:
3157 Form_pg_opclass opcForm
;
3162 opcTup
= SearchSysCache1(CLAOID
,
3163 ObjectIdGetDatum(object
->objectId
));
3164 if (!HeapTupleIsValid(opcTup
))
3167 elog(ERROR
, "cache lookup failed for opclass %u",
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
))
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
);
3197 case OCLASS_OPFAMILY
:
3198 getOpFamilyDescription(&buffer
, object
->objectId
, missing_ok
);
3205 tup
= SearchSysCache1(AMOID
,
3206 ObjectIdGetDatum(object
->objectId
));
3207 if (!HeapTupleIsValid(tup
))
3210 elog(ERROR
, "cache lookup failed for access method %u",
3215 appendStringInfo(&buffer
, _("access method %s"),
3216 NameStr(((Form_pg_am
) GETSTRUCT(tup
))->amname
));
3217 ReleaseSysCache(tup
);
3225 ScanKeyData skey
[1];
3227 Form_pg_amop amopForm
;
3228 StringInfoData opfam
;
3230 amopDesc
= table_open(AccessMethodOperatorRelationId
,
3233 ScanKeyInit(&skey
[0],
3235 BTEqualStrategyNumber
, F_OIDEQ
,
3236 ObjectIdGetDatum(object
->objectId
));
3238 amscan
= systable_beginscan(amopDesc
, AccessMethodOperatorOidIndexId
, true,
3241 tup
= systable_getnext(amscan
);
3243 if (!HeapTupleIsValid(tup
))
3246 elog(ERROR
, "could not find tuple for amop entry %u",
3249 systable_endscan(amscan
);
3250 table_close(amopDesc
, AccessShareLock
);
3254 amopForm
= (Form_pg_amop
) GETSTRUCT(tup
);
3256 initStringInfo(&opfam
);
3257 getOpFamilyDescription(&opfam
, amopForm
->amopfamily
, false);
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
),
3269 format_operator(amopForm
->amopopr
));
3273 systable_endscan(amscan
);
3274 table_close(amopDesc
, AccessShareLock
);
3280 Relation amprocDesc
;
3281 ScanKeyData skey
[1];
3284 Form_pg_amproc amprocForm
;
3285 StringInfoData opfam
;
3287 amprocDesc
= table_open(AccessMethodProcedureRelationId
,
3290 ScanKeyInit(&skey
[0],
3292 BTEqualStrategyNumber
, F_OIDEQ
,
3293 ObjectIdGetDatum(object
->objectId
));
3295 amscan
= systable_beginscan(amprocDesc
, AccessMethodProcedureOidIndexId
, true,
3298 tup
= systable_getnext(amscan
);
3300 if (!HeapTupleIsValid(tup
))
3303 elog(ERROR
, "could not find tuple for amproc entry %u",
3306 systable_endscan(amscan
);
3307 table_close(amprocDesc
, AccessShareLock
);
3311 amprocForm
= (Form_pg_amproc
) GETSTRUCT(tup
);
3313 initStringInfo(&opfam
);
3314 getOpFamilyDescription(&opfam
, amprocForm
->amprocfamily
, false);
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
),
3326 format_procedure(amprocForm
->amproc
));
3330 systable_endscan(amscan
);
3331 table_close(amprocDesc
, AccessShareLock
);
3335 case OCLASS_REWRITE
:
3338 ScanKeyData skey
[1];
3341 Form_pg_rewrite rule
;
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,
3354 tup
= systable_getnext(rcscan
);
3356 if (!HeapTupleIsValid(tup
))
3359 elog(ERROR
, "could not find tuple for rule %u",
3362 systable_endscan(rcscan
);
3363 table_close(ruleDesc
, AccessShareLock
);
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
);
3376 systable_endscan(rcscan
);
3377 table_close(ruleDesc
, AccessShareLock
);
3381 case OCLASS_TRIGGER
:
3384 ScanKeyData skey
[1];
3387 Form_pg_trigger trig
;
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,
3400 tup
= systable_getnext(tgscan
);
3402 if (!HeapTupleIsValid(tup
))
3405 elog(ERROR
, "could not find tuple for trigger %u",
3408 systable_endscan(tgscan
);
3409 table_close(trigDesc
, AccessShareLock
);
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
);
3422 systable_endscan(tgscan
);
3423 table_close(trigDesc
, AccessShareLock
);
3431 nspname
= get_namespace_name(object
->objectId
);
3435 elog(ERROR
, "cache lookup failed for namespace %u",
3439 appendStringInfo(&buffer
, _("schema %s"), nspname
);
3443 case OCLASS_STATISTIC_EXT
:
3446 Form_pg_statistic_ext stxForm
;
3449 stxTup
= SearchSysCache1(STATEXTOID
,
3450 ObjectIdGetDatum(object
->objectId
));
3451 if (!HeapTupleIsValid(stxTup
))
3454 elog(ERROR
, "could not find tuple for statistics object %u",
3459 stxForm
= (Form_pg_statistic_ext
) GETSTRUCT(stxTup
);
3461 /* Qualify the name if not visible in search path */
3462 if (StatisticsObjIsVisible(object
->objectId
))
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
);
3475 case OCLASS_TSPARSER
:
3478 Form_pg_ts_parser prsForm
;
3481 tup
= SearchSysCache1(TSPARSEROID
,
3482 ObjectIdGetDatum(object
->objectId
));
3483 if (!HeapTupleIsValid(tup
))
3486 elog(ERROR
, "cache lookup failed for text search parser %u",
3490 prsForm
= (Form_pg_ts_parser
) GETSTRUCT(tup
);
3492 /* Qualify the name if not visible in search path */
3493 if (TSParserIsVisible(object
->objectId
))
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
);
3508 Form_pg_ts_dict dictForm
;
3511 tup
= SearchSysCache1(TSDICTOID
,
3512 ObjectIdGetDatum(object
->objectId
));
3513 if (!HeapTupleIsValid(tup
))
3516 elog(ERROR
, "cache lookup failed for text search dictionary %u",
3521 dictForm
= (Form_pg_ts_dict
) GETSTRUCT(tup
);
3523 /* Qualify the name if not visible in search path */
3524 if (TSDictionaryIsVisible(object
->objectId
))
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
);
3536 case OCLASS_TSTEMPLATE
:
3539 Form_pg_ts_template tmplForm
;
3542 tup
= SearchSysCache1(TSTEMPLATEOID
,
3543 ObjectIdGetDatum(object
->objectId
));
3544 if (!HeapTupleIsValid(tup
))
3547 elog(ERROR
, "cache lookup failed for text search template %u",
3552 tmplForm
= (Form_pg_ts_template
) GETSTRUCT(tup
);
3554 /* Qualify the name if not visible in search path */
3555 if (TSTemplateIsVisible(object
->objectId
))
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
);
3567 case OCLASS_TSCONFIG
:
3570 Form_pg_ts_config cfgForm
;
3573 tup
= SearchSysCache1(TSCONFIGOID
,
3574 ObjectIdGetDatum(object
->objectId
));
3575 if (!HeapTupleIsValid(tup
))
3578 elog(ERROR
, "cache lookup failed for text search configuration %u",
3583 cfgForm
= (Form_pg_ts_config
) GETSTRUCT(tup
);
3585 /* Qualify the name if not visible in search path */
3586 if (TSConfigIsVisible(object
->objectId
))
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
);
3600 char *username
= GetUserNameFromId(object
->objectId
,
3604 appendStringInfo(&buffer
, _("role %s"), username
);
3608 case OCLASS_ROLE_MEMBERSHIP
:
3611 ScanKeyData skey
[1];
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,
3626 tup
= systable_getnext(rcscan
);
3628 if (!HeapTupleIsValid(tup
))
3631 elog(ERROR
, "could not find tuple for role membership %u",
3634 systable_endscan(rcscan
);
3635 table_close(amDesc
, AccessShareLock
);
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
);
3650 case OCLASS_DATABASE
:
3654 datname
= get_database_name(object
->objectId
);
3658 elog(ERROR
, "cache lookup failed for database %u",
3662 appendStringInfo(&buffer
, _("database %s"), datname
);
3666 case OCLASS_TBLSPACE
:
3670 tblspace
= get_tablespace_name(object
->objectId
);
3674 elog(ERROR
, "cache lookup failed for tablespace %u",
3678 appendStringInfo(&buffer
, _("tablespace %s"), tblspace
);
3684 ForeignDataWrapper
*fdw
;
3686 fdw
= GetForeignDataWrapperExtended(object
->objectId
,
3689 appendStringInfo(&buffer
, _("foreign-data wrapper %s"), fdw
->fdwname
);
3693 case OCLASS_FOREIGN_SERVER
:
3697 srv
= GetForeignServerExtended(object
->objectId
, missing_ok
);
3699 appendStringInfo(&buffer
, _("server %s"), srv
->servername
);
3703 case OCLASS_USER_MAPPING
:
3708 Form_pg_user_mapping umform
;
3711 tup
= SearchSysCache1(USERMAPPINGOID
,
3712 ObjectIdGetDatum(object
->objectId
));
3713 if (!HeapTupleIsValid(tup
))
3716 elog(ERROR
, "cache lookup failed for user mapping %u",
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);
3732 appendStringInfo(&buffer
, _("user mapping for %s on server %s"), usename
,
3740 ScanKeyData skey
[1];
3743 Form_pg_default_acl defacl
;
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
))
3762 elog(ERROR
, "could not find tuple for default ACL %u",
3765 systable_endscan(rcscan
);
3766 table_close(defaclrel
, AccessShareLock
);
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
);
3779 switch (defacl
->defaclobjtype
)
3781 case DEFACLOBJ_RELATION
:
3783 appendStringInfo(&buffer
,
3784 _("default privileges on new relations belonging to role %s in schema %s"),
3787 appendStringInfo(&buffer
,
3788 _("default privileges on new relations belonging to role %s"),
3791 case DEFACLOBJ_SEQUENCE
:
3793 appendStringInfo(&buffer
,
3794 _("default privileges on new sequences belonging to role %s in schema %s"),
3797 appendStringInfo(&buffer
,
3798 _("default privileges on new sequences belonging to role %s"),
3801 case DEFACLOBJ_FUNCTION
:
3803 appendStringInfo(&buffer
,
3804 _("default privileges on new functions belonging to role %s in schema %s"),
3807 appendStringInfo(&buffer
,
3808 _("default privileges on new functions belonging to role %s"),
3811 case DEFACLOBJ_TYPE
:
3813 appendStringInfo(&buffer
,
3814 _("default privileges on new types belonging to role %s in schema %s"),
3817 appendStringInfo(&buffer
,
3818 _("default privileges on new types belonging to role %s"),
3821 case DEFACLOBJ_NAMESPACE
:
3823 appendStringInfo(&buffer
,
3824 _("default privileges on new schemas belonging to role %s"),
3828 /* shouldn't get here */
3830 appendStringInfo(&buffer
,
3831 _("default privileges belonging to role %s in schema %s"),
3834 appendStringInfo(&buffer
,
3835 _("default privileges belonging to role %s"),
3840 systable_endscan(rcscan
);
3841 table_close(defaclrel
, AccessShareLock
);
3845 case OCLASS_EXTENSION
:
3849 extname
= get_extension_name(object
->objectId
);
3853 elog(ERROR
, "cache lookup failed for extension %u",
3857 appendStringInfo(&buffer
, _("extension %s"), extname
);
3861 case OCLASS_EVENT_TRIGGER
:
3865 tup
= SearchSysCache1(EVENTTRIGGEROID
,
3866 ObjectIdGetDatum(object
->objectId
));
3867 if (!HeapTupleIsValid(tup
))
3870 elog(ERROR
, "cache lookup failed for event trigger %u",
3874 appendStringInfo(&buffer
, _("event trigger %s"),
3875 NameStr(((Form_pg_event_trigger
) GETSTRUCT(tup
))->evtname
));
3876 ReleaseSysCache(tup
);
3880 case OCLASS_PARAMETER_ACL
:
3887 tup
= SearchSysCache1(PARAMETERACLOID
,
3888 ObjectIdGetDatum(object
->objectId
));
3889 if (!HeapTupleIsValid(tup
))
3892 elog(ERROR
, "cache lookup failed for parameter ACL %u",
3896 nameDatum
= SysCacheGetAttr(PARAMETERACLOID
, tup
,
3897 Anum_pg_parameter_acl_parname
,
3900 parname
= TextDatumGetCString(nameDatum
);
3901 appendStringInfo(&buffer
, _("parameter %s"), parname
);
3902 ReleaseSysCache(tup
);
3908 Relation policy_rel
;
3909 ScanKeyData skey
[1];
3912 Form_pg_policy form_policy
;
3915 policy_rel
= table_open(PolicyRelationId
, AccessShareLock
);
3917 ScanKeyInit(&skey
[0],
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
))
3930 elog(ERROR
, "could not find tuple for policy %u",
3933 systable_endscan(sscan
);
3934 table_close(policy_rel
, AccessShareLock
);
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
);
3947 systable_endscan(sscan
);
3948 table_close(policy_rel
, AccessShareLock
);
3952 case OCLASS_PUBLICATION
:
3954 char *pubname
= get_publication_name(object
->objectId
,
3958 appendStringInfo(&buffer
, _("publication %s"), pubname
);
3962 case OCLASS_PUBLICATION_NAMESPACE
:
3967 if (!getPublicationSchemaInfo(object
, missing_ok
,
3968 &pubname
, &nspname
))
3971 appendStringInfo(&buffer
, _("publication of schema %s in publication %s"),
3978 case OCLASS_PUBLICATION_REL
:
3982 Form_pg_publication_rel prform
;
3985 tup
= SearchSysCache1(PUBLICATIONREL
,
3986 ObjectIdGetDatum(object
->objectId
));
3987 if (!HeapTupleIsValid(tup
))
3990 elog(ERROR
, "cache lookup failed for publication table %u",
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"),
4005 ReleaseSysCache(tup
);
4009 case OCLASS_SUBSCRIPTION
:
4011 char *subname
= get_subscription_name(object
->objectId
,
4015 appendStringInfo(&buffer
, _("subscription %s"), subname
);
4019 case OCLASS_TRANSFORM
:
4022 Form_pg_transform trfForm
;
4024 trfTup
= SearchSysCache1(TRFOID
,
4025 ObjectIdGetDatum(object
->objectId
));
4026 if (!HeapTupleIsValid(trfTup
))
4029 elog(ERROR
, "could not find tuple for transform %u",
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
);
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)
4058 * getObjectDescriptionOids: as above, except the object is specified by Oids
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".
4078 getRelationDescription(StringInfo buffer
, Oid relid
, bool missing_ok
)
4081 Form_pg_class relForm
;
4085 relTup
= SearchSysCache1(RELOID
,
4086 ObjectIdGetDatum(relid
));
4087 if (!HeapTupleIsValid(relTup
))
4090 elog(ERROR
, "cache lookup failed for relation %u", relid
);
4093 relForm
= (Form_pg_class
) GETSTRUCT(relTup
);
4095 /* Qualify the name if not visible in search path */
4096 if (RelationIsVisible(relid
))
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"),
4111 case RELKIND_PARTITIONED_INDEX
:
4112 appendStringInfo(buffer
, _("index %s"),
4115 case RELKIND_SEQUENCE
:
4116 appendStringInfo(buffer
, _("sequence %s"),
4119 case RELKIND_TOASTVALUE
:
4120 appendStringInfo(buffer
, _("toast table %s"),
4124 appendStringInfo(buffer
, _("view %s"),
4127 case RELKIND_MATVIEW
:
4128 appendStringInfo(buffer
, _("materialized view %s"),
4131 case RELKIND_COMPOSITE_TYPE
:
4132 appendStringInfo(buffer
, _("composite type %s"),
4135 case RELKIND_FOREIGN_TABLE
:
4136 appendStringInfo(buffer
, _("foreign table %s"),
4140 /* shouldn't get here */
4141 appendStringInfo(buffer
, _("relation %s"),
4146 ReleaseSysCache(relTup
);
4150 * subroutine for getObjectDescription: describe an operator family
4153 getOpFamilyDescription(StringInfo buffer
, Oid opfid
, bool missing_ok
)
4156 Form_pg_opfamily opfForm
;
4161 opfTup
= SearchSysCache1(OPFAMILYOID
, ObjectIdGetDatum(opfid
));
4162 if (!HeapTupleIsValid(opfTup
))
4165 elog(ERROR
, "cache lookup failed for opfamily %u", opfid
);
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
))
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
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);
4201 ObjectAddress address
;
4203 /* for "pinned" items in pg_depend, return null */
4204 if (!OidIsValid(classid
) && !OidIsValid(objid
))
4207 address
.classId
= classid
;
4208 address
.objectId
= objid
;
4209 address
.objectSubId
= objsubid
;
4211 description
= getObjectDescription(&address
, true);
4213 if (description
== NULL
)
4216 PG_RETURN_TEXT_P(cstring_to_text(description
));
4220 * SQL-level callable function to obtain object type + identity
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
;
4231 ObjectAddress address
;
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",
4248 TupleDescInitEntry(tupdesc
, (AttrNumber
) 2, "schema",
4250 TupleDescInitEntry(tupdesc
, (AttrNumber
) 3, "name",
4252 TupleDescInitEntry(tupdesc
, (AttrNumber
) 4, "identity",
4255 tupdesc
= BlessTupleDesc(tupdesc
);
4257 if (is_objectclass_supported(address
.classId
))
4260 Relation catalog
= table_open(address
.classId
, AccessShareLock
);
4262 objtup
= get_catalog_object_by_oid(catalog
,
4263 get_object_attnum_oid(address
.classId
),
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
);
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
)
4292 nameDatum
= heap_getattr(objtup
, nameAttnum
,
4293 RelationGetDescr(catalog
), &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));
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);
4316 if (OidIsValid(schema_oid
) && objidentity
)
4318 const char *schema
= quote_identifier(get_namespace_name(schema_oid
));
4320 values
[1] = CStringGetTextDatum(schema
);
4327 if (objname
&& objidentity
)
4329 values
[2] = CStringGetTextDatum(objname
);
4335 /* object identity */
4338 values
[3] = CStringGetTextDatum(objidentity
);
4344 htup
= heap_form_tuple(tupdesc
, values
, nulls
);
4346 PG_RETURN_DATUM(HeapTupleGetDatum(htup
));
4350 * SQL-level callable function to obtain object type + identity
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
;
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",
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));
4389 /* object identity */
4390 identity
= getObjectIdentityParts(&address
, &names
, &args
, true);
4391 if (identity
== NULL
)
4402 values
[1] = PointerGetDatum(strlist_to_textarray(names
));
4404 values
[1] = PointerGetDatum(construct_empty_array(TEXTOID
));
4409 values
[2] = PointerGetDatum(strlist_to_textarray(args
));
4411 values
[2] = PointerGetDatum(construct_empty_array(TEXTOID
));
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.
4427 getObjectTypeDescription(const ObjectAddress
*object
, bool missing_ok
)
4429 StringInfoData buffer
;
4431 initStringInfo(&buffer
);
4433 switch (getObjectClass(object
))
4436 getRelationTypeDescription(&buffer
, object
->objectId
,
4437 object
->objectSubId
,
4442 getProcedureTypeDescription(&buffer
, object
->objectId
,
4447 appendStringInfoString(&buffer
, "type");
4451 appendStringInfoString(&buffer
, "cast");
4454 case OCLASS_COLLATION
:
4455 appendStringInfoString(&buffer
, "collation");
4458 case OCLASS_CONSTRAINT
:
4459 getConstraintTypeDescription(&buffer
, object
->objectId
,
4463 case OCLASS_CONVERSION
:
4464 appendStringInfoString(&buffer
, "conversion");
4467 case OCLASS_DEFAULT
:
4468 appendStringInfoString(&buffer
, "default value");
4471 case OCLASS_LANGUAGE
:
4472 appendStringInfoString(&buffer
, "language");
4475 case OCLASS_LARGEOBJECT
:
4476 appendStringInfoString(&buffer
, "large object");
4479 case OCLASS_OPERATOR
:
4480 appendStringInfoString(&buffer
, "operator");
4483 case OCLASS_OPCLASS
:
4484 appendStringInfoString(&buffer
, "operator class");
4487 case OCLASS_OPFAMILY
:
4488 appendStringInfoString(&buffer
, "operator family");
4492 appendStringInfoString(&buffer
, "access method");
4496 appendStringInfoString(&buffer
, "operator of access method");
4500 appendStringInfoString(&buffer
, "function of access method");
4503 case OCLASS_REWRITE
:
4504 appendStringInfoString(&buffer
, "rule");
4507 case OCLASS_TRIGGER
:
4508 appendStringInfoString(&buffer
, "trigger");
4512 appendStringInfoString(&buffer
, "schema");
4515 case OCLASS_STATISTIC_EXT
:
4516 appendStringInfoString(&buffer
, "statistics object");
4519 case OCLASS_TSPARSER
:
4520 appendStringInfoString(&buffer
, "text search parser");
4524 appendStringInfoString(&buffer
, "text search dictionary");
4527 case OCLASS_TSTEMPLATE
:
4528 appendStringInfoString(&buffer
, "text search template");
4531 case OCLASS_TSCONFIG
:
4532 appendStringInfoString(&buffer
, "text search configuration");
4536 appendStringInfoString(&buffer
, "role");
4539 case OCLASS_ROLE_MEMBERSHIP
:
4540 appendStringInfoString(&buffer
, "role membership");
4543 case OCLASS_DATABASE
:
4544 appendStringInfoString(&buffer
, "database");
4547 case OCLASS_TBLSPACE
:
4548 appendStringInfoString(&buffer
, "tablespace");
4552 appendStringInfoString(&buffer
, "foreign-data wrapper");
4555 case OCLASS_FOREIGN_SERVER
:
4556 appendStringInfoString(&buffer
, "server");
4559 case OCLASS_USER_MAPPING
:
4560 appendStringInfoString(&buffer
, "user mapping");
4564 appendStringInfoString(&buffer
, "default acl");
4567 case OCLASS_EXTENSION
:
4568 appendStringInfoString(&buffer
, "extension");
4571 case OCLASS_EVENT_TRIGGER
:
4572 appendStringInfoString(&buffer
, "event trigger");
4575 case OCLASS_PARAMETER_ACL
:
4576 appendStringInfoString(&buffer
, "parameter ACL");
4580 appendStringInfoString(&buffer
, "policy");
4583 case OCLASS_PUBLICATION
:
4584 appendStringInfoString(&buffer
, "publication");
4587 case OCLASS_PUBLICATION_NAMESPACE
:
4588 appendStringInfoString(&buffer
, "publication namespace");
4591 case OCLASS_PUBLICATION_REL
:
4592 appendStringInfoString(&buffer
, "publication relation");
4595 case OCLASS_SUBSCRIPTION
:
4596 appendStringInfoString(&buffer
, "subscription");
4599 case OCLASS_TRANSFORM
:
4600 appendStringInfoString(&buffer
, "transform");
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);
4616 * subroutine for getObjectTypeDescription: describe a relation type
4619 getRelationTypeDescription(StringInfo buffer
, Oid relid
, int32 objectSubId
,
4623 Form_pg_class relForm
;
4625 relTup
= SearchSysCache1(RELOID
,
4626 ObjectIdGetDatum(relid
));
4627 if (!HeapTupleIsValid(relTup
))
4630 elog(ERROR
, "cache lookup failed for relation %u", relid
);
4632 /* fallback to "relation" for an undefined object */
4633 appendStringInfoString(buffer
, "relation");
4636 relForm
= (Form_pg_class
) GETSTRUCT(relTup
);
4638 switch (relForm
->relkind
)
4640 case RELKIND_RELATION
:
4641 case RELKIND_PARTITIONED_TABLE
:
4642 appendStringInfoString(buffer
, "table");
4645 case RELKIND_PARTITIONED_INDEX
:
4646 appendStringInfoString(buffer
, "index");
4648 case RELKIND_SEQUENCE
:
4649 appendStringInfoString(buffer
, "sequence");
4651 case RELKIND_TOASTVALUE
:
4652 appendStringInfoString(buffer
, "toast table");
4655 appendStringInfoString(buffer
, "view");
4657 case RELKIND_MATVIEW
:
4658 appendStringInfoString(buffer
, "materialized view");
4660 case RELKIND_COMPOSITE_TYPE
:
4661 appendStringInfoString(buffer
, "composite type");
4663 case RELKIND_FOREIGN_TABLE
:
4664 appendStringInfoString(buffer
, "foreign table");
4667 /* shouldn't get here */
4668 appendStringInfoString(buffer
, "relation");
4672 if (objectSubId
!= 0)
4673 appendStringInfoString(buffer
, " column");
4675 ReleaseSysCache(relTup
);
4679 * subroutine for getObjectTypeDescription: describe a constraint type
4682 getConstraintTypeDescription(StringInfo buffer
, Oid constroid
, bool missing_ok
)
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
,
4691 if (!HeapTupleIsValid(constrTup
))
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");
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");
4710 elog(ERROR
, "invalid constraint %u", constrForm
->oid
);
4712 table_close(constrRel
, AccessShareLock
);
4716 * subroutine for getObjectTypeDescription: describe a procedure type
4719 getProcedureTypeDescription(StringInfo buffer
, Oid procid
,
4723 Form_pg_proc procForm
;
4725 procTup
= SearchSysCache1(PROCOID
,
4726 ObjectIdGetDatum(procid
));
4727 if (!HeapTupleIsValid(procTup
))
4730 elog(ERROR
, "cache lookup failed for procedure %u", procid
);
4732 /* fallback to "procedure" for an undefined object */
4733 appendStringInfoString(buffer
, "routine");
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
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.
4771 getObjectIdentityParts(const ObjectAddress
*object
,
4772 List
**objname
, List
**objargs
,
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
));
4792 switch (getObjectClass(object
))
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
,
4808 if (missing_ok
&& attr
== NULL
)
4812 getRelationIdentity(&buffer
, object
->objectId
, objname
,
4814 if (objname
&& *objname
== NIL
)
4819 appendStringInfo(&buffer
, ".%s",
4820 quote_identifier(attr
));
4822 *objname
= lappend(*objname
, attr
);
4829 bits16 flags
= FORMAT_PROC_FORCE_QUALIFY
| FORMAT_PROC_INVALID_AS_NULL
;
4830 char *proname
= format_procedure_extended(object
->objectId
,
4833 if (proname
== NULL
)
4836 appendStringInfoString(&buffer
, proname
);
4838 format_procedure_parts(object
->objectId
, objname
, objargs
,
4845 bits16 flags
= FORMAT_TYPE_INVALID_AS_NULL
| FORMAT_TYPE_FORCE_QUALIFY
;
4848 typeout
= format_type_extended(object
->objectId
, -1, flags
);
4850 if (typeout
== NULL
)
4853 appendStringInfoString(&buffer
, typeout
);
4855 *objname
= list_make1(typeout
);
4863 Form_pg_cast castForm
;
4865 castRel
= table_open(CastRelationId
, AccessShareLock
);
4867 tup
= get_catalog_object_by_oid(castRel
, Anum_pg_cast_oid
,
4870 if (!HeapTupleIsValid(tup
))
4873 elog(ERROR
, "could not find tuple for cast %u",
4876 table_close(castRel
, AccessShareLock
);
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
));
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
);
4896 case OCLASS_COLLATION
:
4899 Form_pg_collation coll
;
4902 collTup
= SearchSysCache1(COLLOID
,
4903 ObjectIdGetDatum(object
->objectId
));
4904 if (!HeapTupleIsValid(collTup
))
4907 elog(ERROR
, "cache lookup failed for collation %u",
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
)));
4917 *objname
= list_make2(schema
,
4918 pstrdup(NameStr(coll
->collname
)));
4919 ReleaseSysCache(collTup
);
4923 case OCLASS_CONSTRAINT
:
4926 Form_pg_constraint con
;
4928 conTup
= SearchSysCache1(CONSTROID
,
4929 ObjectIdGetDatum(object
->objectId
));
4930 if (!HeapTupleIsValid(conTup
))
4933 elog(ERROR
, "cache lookup failed for constraint %u",
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
,
4946 *objname
= lappend(*objname
, pstrdup(NameStr(con
->conname
)));
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
,
4963 *objargs
= lappend(*objargs
, pstrdup(NameStr(con
->conname
)));
4966 ReleaseSysCache(conTup
);
4970 case OCLASS_CONVERSION
:
4973 Form_pg_conversion conForm
;
4976 conTup
= SearchSysCache1(CONVOID
,
4977 ObjectIdGetDatum(object
->objectId
));
4978 if (!HeapTupleIsValid(conTup
))
4981 elog(ERROR
, "cache lookup failed for conversion %u",
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
)));
4991 *objname
= list_make2(schema
,
4992 pstrdup(NameStr(conForm
->conname
)));
4993 ReleaseSysCache(conTup
);
4997 case OCLASS_DEFAULT
:
4999 ObjectAddress colobject
;
5001 colobject
= GetAttrDefaultColumnAddress(object
->objectId
);
5003 if (!OidIsValid(colobject
.objectId
))
5006 elog(ERROR
, "could not find tuple for attrdef %u",
5011 appendStringInfo(&buffer
, "for %s",
5012 getObjectIdentityParts(&colobject
,
5018 case OCLASS_LANGUAGE
:
5021 Form_pg_language langForm
;
5023 langTup
= SearchSysCache1(LANGOID
,
5024 ObjectIdGetDatum(object
->objectId
));
5025 if (!HeapTupleIsValid(langTup
))
5028 elog(ERROR
, "cache lookup failed for language %u",
5032 langForm
= (Form_pg_language
) GETSTRUCT(langTup
);
5033 appendStringInfoString(&buffer
,
5034 quote_identifier(NameStr(langForm
->lanname
)));
5036 *objname
= list_make1(pstrdup(NameStr(langForm
->lanname
)));
5037 ReleaseSysCache(langTup
);
5040 case OCLASS_LARGEOBJECT
:
5041 if (!LargeObjectExists(object
->objectId
))
5043 appendStringInfo(&buffer
, "%u",
5046 *objname
= list_make1(psprintf("%u", object
->objectId
));
5049 case OCLASS_OPERATOR
:
5051 bits16 flags
= FORMAT_OPERATOR_FORCE_QUALIFY
| FORMAT_OPERATOR_INVALID_AS_NULL
;
5052 char *oprname
= format_operator_extended(object
->objectId
,
5055 if (oprname
== NULL
)
5058 appendStringInfoString(&buffer
, oprname
);
5060 format_operator_parts(object
->objectId
, objname
, objargs
, missing_ok
);
5064 case OCLASS_OPCLASS
:
5067 Form_pg_opclass opcForm
;
5072 opcTup
= SearchSysCache1(CLAOID
,
5073 ObjectIdGetDatum(object
->objectId
));
5074 if (!HeapTupleIsValid(opcTup
))
5077 elog(ERROR
, "cache lookup failed for opclass %u",
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
)));
5096 *objname
= list_make3(pstrdup(NameStr(amForm
->amname
)),
5098 pstrdup(NameStr(opcForm
->opcname
)));
5100 ReleaseSysCache(amTup
);
5101 ReleaseSysCache(opcTup
);
5105 case OCLASS_OPFAMILY
:
5106 getOpFamilyIdentity(&buffer
, object
->objectId
, objname
,
5114 amname
= get_am_name(object
->objectId
);
5118 elog(ERROR
, "cache lookup failed for access method %u",
5122 appendStringInfoString(&buffer
, quote_identifier(amname
));
5124 *objname
= list_make1(amname
);
5132 ScanKeyData skey
[1];
5134 Form_pg_amop amopForm
;
5135 StringInfoData opfam
;
5139 amopDesc
= table_open(AccessMethodOperatorRelationId
,
5142 ScanKeyInit(&skey
[0],
5144 BTEqualStrategyNumber
, F_OIDEQ
,
5145 ObjectIdGetDatum(object
->objectId
));
5147 amscan
= systable_beginscan(amopDesc
, AccessMethodOperatorOidIndexId
, true,
5150 tup
= systable_getnext(amscan
);
5152 if (!HeapTupleIsValid(tup
))
5155 elog(ERROR
, "could not find tuple for amop entry %u",
5158 systable_endscan(amscan
);
5159 table_close(amopDesc
, AccessShareLock
);
5163 amopForm
= (Form_pg_amop
) GETSTRUCT(tup
);
5165 initStringInfo(&opfam
);
5166 getOpFamilyIdentity(&opfam
, amopForm
->amopfamily
, objname
,
5169 ltype
= format_type_be_qualified(amopForm
->amoplefttype
);
5170 rtype
= format_type_be_qualified(amopForm
->amoprighttype
);
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
);
5185 systable_endscan(amscan
);
5186 table_close(amopDesc
, AccessShareLock
);
5192 Relation amprocDesc
;
5193 ScanKeyData skey
[1];
5196 Form_pg_amproc amprocForm
;
5197 StringInfoData opfam
;
5201 amprocDesc
= table_open(AccessMethodProcedureRelationId
,
5204 ScanKeyInit(&skey
[0],
5206 BTEqualStrategyNumber
, F_OIDEQ
,
5207 ObjectIdGetDatum(object
->objectId
));
5209 amscan
= systable_beginscan(amprocDesc
, AccessMethodProcedureOidIndexId
, true,
5212 tup
= systable_getnext(amscan
);
5214 if (!HeapTupleIsValid(tup
))
5217 elog(ERROR
, "could not find tuple for amproc entry %u",
5220 systable_endscan(amscan
);
5221 table_close(amprocDesc
, AccessShareLock
);
5225 amprocForm
= (Form_pg_amproc
) GETSTRUCT(tup
);
5227 initStringInfo(&opfam
);
5228 getOpFamilyIdentity(&opfam
, amprocForm
->amprocfamily
, objname
,
5231 ltype
= format_type_be_qualified(amprocForm
->amproclefttype
);
5232 rtype
= format_type_be_qualified(amprocForm
->amprocrighttype
);
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
);
5247 systable_endscan(amscan
);
5248 table_close(amprocDesc
, AccessShareLock
);
5252 case OCLASS_REWRITE
:
5256 Form_pg_rewrite rule
;
5258 ruleDesc
= table_open(RewriteRelationId
, AccessShareLock
);
5260 tup
= get_catalog_object_by_oid(ruleDesc
, Anum_pg_rewrite_oid
,
5263 if (!HeapTupleIsValid(tup
))
5266 elog(ERROR
, "could not find tuple for rule %u",
5269 table_close(ruleDesc
, AccessShareLock
);
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);
5279 *objname
= lappend(*objname
, pstrdup(NameStr(rule
->rulename
)));
5281 table_close(ruleDesc
, AccessShareLock
);
5285 case OCLASS_TRIGGER
:
5289 Form_pg_trigger trig
;
5291 trigDesc
= table_open(TriggerRelationId
, AccessShareLock
);
5293 tup
= get_catalog_object_by_oid(trigDesc
, Anum_pg_trigger_oid
,
5296 if (!HeapTupleIsValid(tup
))
5299 elog(ERROR
, "could not find tuple for trigger %u",
5302 table_close(trigDesc
, AccessShareLock
);
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);
5312 *objname
= lappend(*objname
, pstrdup(NameStr(trig
->tgname
)));
5314 table_close(trigDesc
, AccessShareLock
);
5322 nspname
= get_namespace_name_or_temp(object
->objectId
);
5326 elog(ERROR
, "cache lookup failed for namespace %u",
5330 appendStringInfoString(&buffer
,
5331 quote_identifier(nspname
));
5333 *objname
= list_make1(nspname
);
5337 case OCLASS_STATISTIC_EXT
:
5340 Form_pg_statistic_ext formStatistic
;
5343 tup
= SearchSysCache1(STATEXTOID
,
5344 ObjectIdGetDatum(object
->objectId
));
5345 if (!HeapTupleIsValid(tup
))
5348 elog(ERROR
, "cache lookup failed for statistics object %u",
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
)));
5358 *objname
= list_make2(schema
,
5359 pstrdup(NameStr(formStatistic
->stxname
)));
5360 ReleaseSysCache(tup
);
5364 case OCLASS_TSPARSER
:
5367 Form_pg_ts_parser formParser
;
5370 tup
= SearchSysCache1(TSPARSEROID
,
5371 ObjectIdGetDatum(object
->objectId
));
5372 if (!HeapTupleIsValid(tup
))
5375 elog(ERROR
, "cache lookup failed for text search parser %u",
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
)));
5385 *objname
= list_make2(schema
,
5386 pstrdup(NameStr(formParser
->prsname
)));
5387 ReleaseSysCache(tup
);
5394 Form_pg_ts_dict formDict
;
5397 tup
= SearchSysCache1(TSDICTOID
,
5398 ObjectIdGetDatum(object
->objectId
));
5399 if (!HeapTupleIsValid(tup
))
5402 elog(ERROR
, "cache lookup failed for text search dictionary %u",
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
)));
5412 *objname
= list_make2(schema
,
5413 pstrdup(NameStr(formDict
->dictname
)));
5414 ReleaseSysCache(tup
);
5418 case OCLASS_TSTEMPLATE
:
5421 Form_pg_ts_template formTmpl
;
5424 tup
= SearchSysCache1(TSTEMPLATEOID
,
5425 ObjectIdGetDatum(object
->objectId
));
5426 if (!HeapTupleIsValid(tup
))
5429 elog(ERROR
, "cache lookup failed for text search template %u",
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
)));
5439 *objname
= list_make2(schema
,
5440 pstrdup(NameStr(formTmpl
->tmplname
)));
5441 ReleaseSysCache(tup
);
5445 case OCLASS_TSCONFIG
:
5448 Form_pg_ts_config formCfg
;
5451 tup
= SearchSysCache1(TSCONFIGOID
,
5452 ObjectIdGetDatum(object
->objectId
));
5453 if (!HeapTupleIsValid(tup
))
5456 elog(ERROR
, "cache lookup failed for text search configuration %u",
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
)));
5466 *objname
= list_make2(schema
,
5467 pstrdup(NameStr(formCfg
->cfgname
)));
5468 ReleaseSysCache(tup
);
5476 username
= GetUserNameFromId(object
->objectId
, missing_ok
);
5480 *objname
= list_make1(username
);
5481 appendStringInfoString(&buffer
,
5482 quote_identifier(username
));
5486 case OCLASS_ROLE_MEMBERSHIP
:
5488 Relation authMemDesc
;
5489 ScanKeyData skey
[1];
5492 Form_pg_auth_members amForm
;
5494 authMemDesc
= table_open(AuthMemRelationId
,
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,
5505 tup
= systable_getnext(amscan
);
5507 if (!HeapTupleIsValid(tup
))
5510 elog(ERROR
, "could not find tuple for pg_auth_members entry %u",
5513 systable_endscan(amscan
);
5514 table_close(authMemDesc
, AccessShareLock
);
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
);
5529 case OCLASS_DATABASE
:
5533 datname
= get_database_name(object
->objectId
);
5537 elog(ERROR
, "cache lookup failed for database %u",
5542 *objname
= list_make1(datname
);
5543 appendStringInfoString(&buffer
,
5544 quote_identifier(datname
));
5548 case OCLASS_TBLSPACE
:
5552 tblspace
= get_tablespace_name(object
->objectId
);
5556 elog(ERROR
, "cache lookup failed for tablespace %u",
5561 *objname
= list_make1(tblspace
);
5562 appendStringInfoString(&buffer
,
5563 quote_identifier(tblspace
));
5569 ForeignDataWrapper
*fdw
;
5571 fdw
= GetForeignDataWrapperExtended(object
->objectId
,
5575 appendStringInfoString(&buffer
, quote_identifier(fdw
->fdwname
));
5577 *objname
= list_make1(pstrdup(fdw
->fdwname
));
5582 case OCLASS_FOREIGN_SERVER
:
5586 srv
= GetForeignServerExtended(object
->objectId
,
5590 appendStringInfoString(&buffer
,
5591 quote_identifier(srv
->servername
));
5593 *objname
= list_make1(pstrdup(srv
->servername
));
5598 case OCLASS_USER_MAPPING
:
5602 Form_pg_user_mapping umform
;
5604 const char *usename
;
5606 tup
= SearchSysCache1(USERMAPPINGOID
,
5607 ObjectIdGetDatum(object
->objectId
));
5608 if (!HeapTupleIsValid(tup
))
5611 elog(ERROR
, "cache lookup failed for user mapping %u",
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);
5628 *objname
= list_make1(pstrdup(usename
));
5629 *objargs
= list_make1(pstrdup(srv
->servername
));
5632 appendStringInfo(&buffer
, "%s on server %s",
5633 quote_identifier(usename
),
5641 ScanKeyData skey
[1];
5644 Form_pg_default_acl defacl
;
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
))
5663 elog(ERROR
, "could not find tuple for default ACL %u",
5666 systable_endscan(rcscan
);
5667 table_close(defaclrel
, AccessShareLock
);
5671 defacl
= (Form_pg_default_acl
) GETSTRUCT(tup
);
5673 username
= GetUserNameFromId(defacl
->defaclrole
, false);
5674 appendStringInfo(&buffer
,
5676 quote_identifier(username
));
5678 if (OidIsValid(defacl
->defaclnamespace
))
5680 schema
= get_namespace_name_or_temp(defacl
->defaclnamespace
);
5681 appendStringInfo(&buffer
,
5683 quote_identifier(schema
));
5688 switch (defacl
->defaclobjtype
)
5690 case DEFACLOBJ_RELATION
:
5691 appendStringInfoString(&buffer
,
5694 case DEFACLOBJ_SEQUENCE
:
5695 appendStringInfoString(&buffer
,
5698 case DEFACLOBJ_FUNCTION
:
5699 appendStringInfoString(&buffer
,
5702 case DEFACLOBJ_TYPE
:
5703 appendStringInfoString(&buffer
,
5706 case DEFACLOBJ_NAMESPACE
:
5707 appendStringInfoString(&buffer
,
5714 *objname
= list_make1(username
);
5716 *objname
= lappend(*objname
, schema
);
5717 *objargs
= list_make1(psprintf("%c", defacl
->defaclobjtype
));
5720 systable_endscan(rcscan
);
5721 table_close(defaclrel
, AccessShareLock
);
5725 case OCLASS_EXTENSION
:
5729 extname
= get_extension_name(object
->objectId
);
5733 elog(ERROR
, "cache lookup failed for extension %u",
5737 appendStringInfoString(&buffer
, quote_identifier(extname
));
5739 *objname
= list_make1(extname
);
5743 case OCLASS_EVENT_TRIGGER
:
5746 Form_pg_event_trigger trigForm
;
5749 tup
= SearchSysCache1(EVENTTRIGGEROID
,
5750 ObjectIdGetDatum(object
->objectId
));
5751 if (!HeapTupleIsValid(tup
))
5754 elog(ERROR
, "cache lookup failed for event trigger %u",
5758 trigForm
= (Form_pg_event_trigger
) GETSTRUCT(tup
);
5759 evtname
= pstrdup(NameStr(trigForm
->evtname
));
5760 appendStringInfoString(&buffer
, quote_identifier(evtname
));
5762 *objname
= list_make1(evtname
);
5763 ReleaseSysCache(tup
);
5767 case OCLASS_PARAMETER_ACL
:
5774 tup
= SearchSysCache1(PARAMETERACLOID
,
5775 ObjectIdGetDatum(object
->objectId
));
5776 if (!HeapTupleIsValid(tup
))
5779 elog(ERROR
, "cache lookup failed for parameter ACL %u",
5783 nameDatum
= SysCacheGetAttr(PARAMETERACLOID
, tup
,
5784 Anum_pg_parameter_acl_parname
,
5787 parname
= TextDatumGetCString(nameDatum
);
5788 appendStringInfoString(&buffer
, parname
);
5790 *objname
= list_make1(parname
);
5791 ReleaseSysCache(tup
);
5799 Form_pg_policy policy
;
5801 polDesc
= table_open(PolicyRelationId
, AccessShareLock
);
5803 tup
= get_catalog_object_by_oid(polDesc
, Anum_pg_policy_oid
,
5806 if (!HeapTupleIsValid(tup
))
5809 elog(ERROR
, "could not find tuple for policy %u",
5812 table_close(polDesc
, AccessShareLock
);
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);
5822 *objname
= lappend(*objname
, pstrdup(NameStr(policy
->polname
)));
5824 table_close(polDesc
, AccessShareLock
);
5828 case OCLASS_PUBLICATION
:
5832 pubname
= get_publication_name(object
->objectId
, missing_ok
);
5835 appendStringInfoString(&buffer
,
5836 quote_identifier(pubname
));
5838 *objname
= list_make1(pubname
);
5843 case OCLASS_PUBLICATION_NAMESPACE
:
5848 if (!getPublicationSchemaInfo(object
, missing_ok
, &pubname
,
5851 appendStringInfo(&buffer
, "%s in publication %s",
5855 *objargs
= list_make1(pubname
);
5860 *objname
= list_make1(nspname
);
5867 case OCLASS_PUBLICATION_REL
:
5871 Form_pg_publication_rel prform
;
5873 tup
= SearchSysCache1(PUBLICATIONREL
,
5874 ObjectIdGetDatum(object
->objectId
));
5875 if (!HeapTupleIsValid(tup
))
5878 elog(ERROR
, "cache lookup failed for publication table %u",
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
);
5890 *objargs
= list_make1(pubname
);
5892 ReleaseSysCache(tup
);
5896 case OCLASS_SUBSCRIPTION
:
5900 subname
= get_subscription_name(object
->objectId
, missing_ok
);
5903 appendStringInfoString(&buffer
,
5904 quote_identifier(subname
));
5906 *objname
= list_make1(subname
);
5911 case OCLASS_TRANSFORM
:
5913 Relation transformDesc
;
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
,
5925 if (!HeapTupleIsValid(tup
))
5928 elog(ERROR
, "could not find tuple for transform %u",
5931 table_close(transformDesc
, AccessShareLock
);
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",
5945 *objname
= list_make1(transformType
);
5946 *objargs
= list_make1(pstrdup(transformLang
));
5949 table_close(transformDesc
, AccessShareLock
);
5954 * There's intentionally no default: case here; we want the
5955 * compiler to warn if a new OCLASS hasn't been handled above.
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
);
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
));
5985 getOpFamilyIdentity(StringInfo buffer
, Oid opfid
, List
**object
,
5989 Form_pg_opfamily opfForm
;
5994 opfTup
= SearchSysCache1(OPFAMILYOID
, ObjectIdGetDatum(opfid
));
5995 if (!HeapTupleIsValid(opfTup
))
5998 elog(ERROR
, "cache lookup failed for opfamily %u", opfid
);
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
));
6016 *object
= list_make3(pstrdup(NameStr(amForm
->amname
)),
6018 pstrdup(NameStr(opfForm
->opfname
)));
6020 ReleaseSysCache(amTup
);
6021 ReleaseSysCache(opfTup
);
6025 * Append the relation identity (quoted qualified name) to the given
6029 getRelationIdentity(StringInfo buffer
, Oid relid
, List
**object
,
6033 Form_pg_class relForm
;
6036 relTup
= SearchSysCache1(RELOID
,
6037 ObjectIdGetDatum(relid
));
6038 if (!HeapTupleIsValid(relTup
))
6041 elog(ERROR
, "cache lookup failed for relation %u", relid
);
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
)));
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.
6063 strlist_to_textarray(List
*list
)
6070 MemoryContext memcxt
;
6071 MemoryContext oldcxt
;
6074 /* Work in a temp context; easier than individually pfree'ing the Datums */
6075 memcxt
= AllocSetContextCreate(CurrentMemoryContext
,
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
));
6085 char *name
= lfirst(cell
);
6090 datums
[j
++] = CStringGetTextDatum(name
);
6096 MemoryContextSwitchTo(oldcxt
);
6099 arr
= construct_md_array(datums
, nulls
, 1, &j
,
6100 lb
, TEXTOID
, -1, false, TYPALIGN_INT
);
6102 MemoryContextDelete(memcxt
);
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.
6118 get_relkind_objtype(char relkind
)
6122 case RELKIND_RELATION
:
6123 case RELKIND_PARTITIONED_TABLE
:
6124 return OBJECT_TABLE
;
6126 case RELKIND_PARTITIONED_INDEX
:
6127 return OBJECT_INDEX
;
6128 case RELKIND_SEQUENCE
:
6129 return OBJECT_SEQUENCE
;
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
;
6139 /* Per above, don't raise an error */
6140 return OBJECT_TABLE
;