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