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