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-2022, 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,
1777  TypeNameToString(typenames[0]),
1778  TypeNameToString(typenames[1]),
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,
1808  TypeNameToString(typenames[0]),
1809  TypeNameToString(typenames[1]),
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]));
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  }
2243  }
2244  else
2245  {
2246  /* For all other object types, use string Values */
2247  args = textarray_to_strvaluelist(argsarr);
2248  }
2249 
2250  /*
2251  * get_object_address is pretty sensitive to the length of its input
2252  * lists; check that they're what it wants.
2253  */
2254  switch (type)
2255  {
2257  case OBJECT_USER_MAPPING:
2258  if (list_length(name) != 1)
2259  ereport(ERROR,
2260  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2261  errmsg("name list length must be exactly %d", 1)));
2262  /* fall through to check args length */
2263  /* FALLTHROUGH */
2264  case OBJECT_DOMCONSTRAINT:
2265  case OBJECT_CAST:
2267  case OBJECT_DEFACL:
2268  case OBJECT_TRANSFORM:
2269  if (list_length(args) != 1)
2270  ereport(ERROR,
2271  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2272  errmsg("argument list length must be exactly %d", 1)));
2273  break;
2274  case OBJECT_OPFAMILY:
2275  case OBJECT_OPCLASS:
2276  if (list_length(name) < 2)
2277  ereport(ERROR,
2278  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2279  errmsg("name list length must be at least %d", 2)));
2280  break;
2281  case OBJECT_AMOP:
2282  case OBJECT_AMPROC:
2283  if (list_length(name) < 3)
2284  ereport(ERROR,
2285  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2286  errmsg("name list length must be at least %d", 3)));
2287  /* fall through to check args length */
2288  /* FALLTHROUGH */
2289  case OBJECT_OPERATOR:
2290  if (list_length(args) != 2)
2291  ereport(ERROR,
2292  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2293  errmsg("argument list length must be exactly %d", 2)));
2294  break;
2295  default:
2296  break;
2297  }
2298 
2299  /*
2300  * Now build the Node type that get_object_address() expects for the given
2301  * type.
2302  */
2303  switch (type)
2304  {
2305  case OBJECT_TABLE:
2306  case OBJECT_SEQUENCE:
2307  case OBJECT_VIEW:
2308  case OBJECT_MATVIEW:
2309  case OBJECT_INDEX:
2310  case OBJECT_FOREIGN_TABLE:
2311  case OBJECT_COLUMN:
2312  case OBJECT_ATTRIBUTE:
2313  case OBJECT_COLLATION:
2314  case OBJECT_CONVERSION:
2315  case OBJECT_STATISTIC_EXT:
2316  case OBJECT_TSPARSER:
2317  case OBJECT_TSDICTIONARY:
2318  case OBJECT_TSTEMPLATE:
2320  case OBJECT_DEFAULT:
2321  case OBJECT_POLICY:
2322  case OBJECT_RULE:
2323  case OBJECT_TRIGGER:
2324  case OBJECT_TABCONSTRAINT:
2325  case OBJECT_OPCLASS:
2326  case OBJECT_OPFAMILY:
2327  objnode = (Node *) name;
2328  break;
2329  case OBJECT_ACCESS_METHOD:
2330  case OBJECT_DATABASE:
2331  case OBJECT_EVENT_TRIGGER:
2332  case OBJECT_EXTENSION:
2333  case OBJECT_FDW:
2334  case OBJECT_FOREIGN_SERVER:
2335  case OBJECT_LANGUAGE:
2336  case OBJECT_PARAMETER_ACL:
2337  case OBJECT_PUBLICATION:
2338  case OBJECT_ROLE:
2339  case OBJECT_SCHEMA:
2340  case OBJECT_SUBSCRIPTION:
2341  case OBJECT_TABLESPACE:
2342  if (list_length(name) != 1)
2343  ereport(ERROR,
2344  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2345  errmsg("name list length must be exactly %d", 1)));
2346  objnode = linitial(name);
2347  break;
2348  case OBJECT_TYPE:
2349  case OBJECT_DOMAIN:
2350  objnode = (Node *) typename;
2351  break;
2352  case OBJECT_CAST:
2353  case OBJECT_DOMCONSTRAINT:
2354  case OBJECT_TRANSFORM:
2355  objnode = (Node *) list_make2(typename, linitial(args));
2356  break;
2358  objnode = (Node *) list_make2(name, linitial(args));
2359  break;
2361  case OBJECT_USER_MAPPING:
2362  objnode = (Node *) list_make2(linitial(name), linitial(args));
2363  break;
2364  case OBJECT_DEFACL:
2365  objnode = (Node *) lcons(linitial(args), name);
2366  break;
2367  case OBJECT_AMOP:
2368  case OBJECT_AMPROC:
2369  objnode = (Node *) list_make2(name, args);
2370  break;
2371  case OBJECT_FUNCTION:
2372  case OBJECT_PROCEDURE:
2373  case OBJECT_ROUTINE:
2374  case OBJECT_AGGREGATE:
2375  case OBJECT_OPERATOR:
2376  {
2378 
2379  owa->objname = name;
2380  owa->objargs = args;
2381  objnode = (Node *) owa;
2382  break;
2383  }
2384  case OBJECT_LARGEOBJECT:
2385  /* already handled above */
2386  break;
2387  /* no default, to let compiler warn about missing case */
2388  }
2389 
2390  if (objnode == NULL)
2391  elog(ERROR, "unrecognized object type: %d", type);
2392 
2393  addr = get_object_address(type, objnode,
2394  &relation, AccessShareLock, false);
2395 
2396  /* We don't need the relcache entry, thank you very much */
2397  if (relation)
2398  relation_close(relation, AccessShareLock);
2399 
2400  tupdesc = CreateTemplateTupleDesc(3);
2401  TupleDescInitEntry(tupdesc, (AttrNumber) 1, "classid",
2402  OIDOID, -1, 0);
2403  TupleDescInitEntry(tupdesc, (AttrNumber) 2, "objid",
2404  OIDOID, -1, 0);
2405  TupleDescInitEntry(tupdesc, (AttrNumber) 3, "objsubid",
2406  INT4OID, -1, 0);
2407  tupdesc = BlessTupleDesc(tupdesc);
2408 
2409  values[0] = ObjectIdGetDatum(addr.classId);
2410  values[1] = ObjectIdGetDatum(addr.objectId);
2411  values[2] = Int32GetDatum(addr.objectSubId);
2412  nulls[0] = false;
2413  nulls[1] = false;
2414  nulls[2] = false;
2415 
2416  htup = heap_form_tuple(tupdesc, values, nulls);
2417 
2419 }
2420 
2421 /*
2422  * Check ownership of an object previously identified by get_object_address.
2423  */
2424 void
2426  Node *object, Relation relation)
2427 {
2428  switch (objtype)
2429  {
2430  case OBJECT_INDEX:
2431  case OBJECT_SEQUENCE:
2432  case OBJECT_TABLE:
2433  case OBJECT_VIEW:
2434  case OBJECT_MATVIEW:
2435  case OBJECT_FOREIGN_TABLE:
2436  case OBJECT_COLUMN:
2437  case OBJECT_RULE:
2438  case OBJECT_TRIGGER:
2439  case OBJECT_POLICY:
2440  case OBJECT_TABCONSTRAINT:
2441  if (!object_ownercheck(RelationRelationId, RelationGetRelid(relation), roleid))
2443  RelationGetRelationName(relation));
2444  break;
2445  case OBJECT_TYPE:
2446  case OBJECT_DOMAIN:
2447  case OBJECT_ATTRIBUTE:
2448  if (!object_ownercheck(address.classId, address.objectId, roleid))
2450  break;
2451  case OBJECT_DOMCONSTRAINT:
2452  {
2453  HeapTuple tuple;
2454  Oid contypid;
2455 
2456  tuple = SearchSysCache1(CONSTROID,
2457  ObjectIdGetDatum(address.objectId));
2458  if (!HeapTupleIsValid(tuple))
2459  elog(ERROR, "constraint with OID %u does not exist",
2460  address.objectId);
2461 
2462  contypid = ((Form_pg_constraint) GETSTRUCT(tuple))->contypid;
2463 
2464  ReleaseSysCache(tuple);
2465 
2466  /*
2467  * Fallback to type ownership check in this case as this is
2468  * what domain constraints rely on.
2469  */
2470  if (!object_ownercheck(TypeRelationId, contypid, roleid))
2472  }
2473  break;
2474  case OBJECT_AGGREGATE:
2475  case OBJECT_FUNCTION:
2476  case OBJECT_PROCEDURE:
2477  case OBJECT_ROUTINE:
2478  case OBJECT_OPERATOR:
2479  if (!object_ownercheck(address.classId, address.objectId, roleid))
2481  NameListToString((castNode(ObjectWithArgs, object))->objname));
2482  break;
2483  case OBJECT_DATABASE:
2484  case OBJECT_EVENT_TRIGGER:
2485  case OBJECT_EXTENSION:
2486  case OBJECT_FDW:
2487  case OBJECT_FOREIGN_SERVER:
2488  case OBJECT_LANGUAGE:
2489  case OBJECT_PUBLICATION:
2490  case OBJECT_SCHEMA:
2491  case OBJECT_SUBSCRIPTION:
2492  case OBJECT_TABLESPACE:
2493  if (!object_ownercheck(address.classId, address.objectId, roleid))
2495  strVal(object));
2496  break;
2497  case OBJECT_COLLATION:
2498  case OBJECT_CONVERSION:
2499  case OBJECT_OPCLASS:
2500  case OBJECT_OPFAMILY:
2501  case OBJECT_STATISTIC_EXT:
2502  case OBJECT_TSDICTIONARY:
2504  if (!object_ownercheck(address.classId, address.objectId, roleid))
2506  NameListToString(castNode(List, object)));
2507  break;
2508  case OBJECT_LARGEOBJECT:
2509  if (!lo_compat_privileges &&
2510  !object_ownercheck(address.classId, address.objectId, roleid))
2511  ereport(ERROR,
2512  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2513  errmsg("must be owner of large object %u",
2514  address.objectId)));
2515  break;
2516  case OBJECT_CAST:
2517  {
2518  /* We can only check permissions on the source/target types */
2519  TypeName *sourcetype = linitial_node(TypeName, castNode(List, object));
2520  TypeName *targettype = lsecond_node(TypeName, castNode(List, object));
2521  Oid sourcetypeid = typenameTypeId(NULL, sourcetype);
2522  Oid targettypeid = typenameTypeId(NULL, targettype);
2523 
2524  if (!object_ownercheck(TypeRelationId, sourcetypeid, roleid)
2525  && !object_ownercheck(TypeRelationId, targettypeid, roleid))
2526  ereport(ERROR,
2527  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2528  errmsg("must be owner of type %s or type %s",
2529  format_type_be(sourcetypeid),
2530  format_type_be(targettypeid))));
2531  }
2532  break;
2533  case OBJECT_TRANSFORM:
2534  {
2535  TypeName *typename = linitial_node(TypeName, castNode(List, object));
2536  Oid typeid = typenameTypeId(NULL, typename);
2537 
2538  if (!object_ownercheck(TypeRelationId, typeid, roleid))
2540  }
2541  break;
2542  case OBJECT_ROLE:
2543 
2544  /*
2545  * We treat roles as being "owned" by those with CREATEROLE priv,
2546  * except that superusers are only owned by superusers.
2547  */
2548  if (superuser_arg(address.objectId))
2549  {
2550  if (!superuser_arg(roleid))
2551  ereport(ERROR,
2552  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2553  errmsg("must be superuser")));
2554  }
2555  else
2556  {
2557  if (!has_createrole_privilege(roleid))
2558  ereport(ERROR,
2559  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2560  errmsg("must have CREATEROLE privilege")));
2561  }
2562  break;
2563  case OBJECT_TSPARSER:
2564  case OBJECT_TSTEMPLATE:
2565  case OBJECT_ACCESS_METHOD:
2566  case OBJECT_PARAMETER_ACL:
2567  /* We treat these object types as being owned by superusers */
2568  if (!superuser_arg(roleid))
2569  ereport(ERROR,
2570  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2571  errmsg("must be superuser")));
2572  break;
2573  case OBJECT_AMOP:
2574  case OBJECT_AMPROC:
2575  case OBJECT_DEFAULT:
2576  case OBJECT_DEFACL:
2579  case OBJECT_USER_MAPPING:
2580  /* These are currently not supported or don't make sense here. */
2581  elog(ERROR, "unsupported object type: %d", (int) objtype);
2582  break;
2583  }
2584 }
2585 
2586 /*
2587  * get_object_namespace
2588  *
2589  * Find the schema containing the specified object. For non-schema objects,
2590  * this function returns InvalidOid.
2591  */
2592 Oid
2594 {
2595  int cache;
2596  HeapTuple tuple;
2597  bool isnull;
2598  Oid oid;
2599  const ObjectPropertyType *property;
2600 
2601  /* If not owned by a namespace, just return InvalidOid. */
2602  property = get_object_property_data(address->classId);
2603  if (property->attnum_namespace == InvalidAttrNumber)
2604  return InvalidOid;
2605 
2606  /* Currently, we can only handle object types with system caches. */
2607  cache = property->oid_catcache_id;
2608  Assert(cache != -1);
2609 
2610  /* Fetch tuple from syscache and extract namespace attribute. */
2611  tuple = SearchSysCache1(cache, ObjectIdGetDatum(address->objectId));
2612  if (!HeapTupleIsValid(tuple))
2613  elog(ERROR, "cache lookup failed for cache %d oid %u",
2614  cache, address->objectId);
2615  oid = DatumGetObjectId(SysCacheGetAttr(cache,
2616  tuple,
2617  property->attnum_namespace,
2618  &isnull));
2619  Assert(!isnull);
2620  ReleaseSysCache(tuple);
2621 
2622  return oid;
2623 }
2624 
2625 /*
2626  * Return ObjectType for the given object type as given by
2627  * getObjectTypeDescription; if no valid ObjectType code exists, but it's a
2628  * possible output type from getObjectTypeDescription, return -1.
2629  * Otherwise, an error is thrown.
2630  */
2631 int
2632 read_objtype_from_string(const char *objtype)
2633 {
2634  int i;
2635 
2636  for (i = 0; i < lengthof(ObjectTypeMap); i++)
2637  {
2638  if (strcmp(ObjectTypeMap[i].tm_name, objtype) == 0)
2639  return ObjectTypeMap[i].tm_type;
2640  }
2641  ereport(ERROR,
2642  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2643  errmsg("unrecognized object type \"%s\"", objtype)));
2644 
2645  return -1; /* keep compiler quiet */
2646 }
2647 
2648 /*
2649  * Interfaces to reference fields of ObjectPropertyType
2650  */
2651 const char *
2653 {
2654  const ObjectPropertyType *prop = get_object_property_data(class_id);
2655 
2656  return prop->class_descr;
2657 }
2658 
2659 Oid
2661 {
2662  const ObjectPropertyType *prop = get_object_property_data(class_id);
2663 
2664  return prop->oid_index_oid;
2665 }
2666 
2667 int
2669 {
2670  const ObjectPropertyType *prop = get_object_property_data(class_id);
2671 
2672  return prop->oid_catcache_id;
2673 }
2674 
2675 int
2677 {
2678  const ObjectPropertyType *prop = get_object_property_data(class_id);
2679 
2680  return prop->name_catcache_id;
2681 }
2682 
2683 AttrNumber
2685 {
2686  const ObjectPropertyType *prop = get_object_property_data(class_id);
2687 
2688  return prop->attnum_oid;
2689 }
2690 
2691 AttrNumber
2693 {
2694  const ObjectPropertyType *prop = get_object_property_data(class_id);
2695 
2696  return prop->attnum_name;
2697 }
2698 
2699 AttrNumber
2701 {
2702  const ObjectPropertyType *prop = get_object_property_data(class_id);
2703 
2704  return prop->attnum_namespace;
2705 }
2706 
2707 AttrNumber
2709 {
2710  const ObjectPropertyType *prop = get_object_property_data(class_id);
2711 
2712  return prop->attnum_owner;
2713 }
2714 
2715 AttrNumber
2717 {
2718  const ObjectPropertyType *prop = get_object_property_data(class_id);
2719 
2720  return prop->attnum_acl;
2721 }
2722 
2723 /*
2724  * get_object_type
2725  *
2726  * Return the object type associated with a given object. This routine
2727  * is primarily used to determine the object type to mention in ACL check
2728  * error messages, so it's desirable for it to avoid failing.
2729  */
2730 ObjectType
2731 get_object_type(Oid class_id, Oid object_id)
2732 {
2733  const ObjectPropertyType *prop = get_object_property_data(class_id);
2734 
2735  if (prop->objtype == OBJECT_TABLE)
2736  {
2737  /*
2738  * If the property data says it's a table, dig a little deeper to get
2739  * the real relation kind, so that callers can produce more precise
2740  * error messages.
2741  */
2742  return get_relkind_objtype(get_rel_relkind(object_id));
2743  }
2744  else
2745  return prop->objtype;
2746 }
2747 
2748 bool
2750 {
2751  const ObjectPropertyType *prop = get_object_property_data(class_id);
2752 
2753  return prop->is_nsp_name_unique;
2754 }
2755 
2756 /*
2757  * Return whether we have useful data for the given object class in the
2758  * ObjectProperty table.
2759  */
2760 bool
2762 {
2763  int index;
2764 
2765  for (index = 0; index < lengthof(ObjectProperty); index++)
2766  {
2767  if (ObjectProperty[index].class_oid == class_id)
2768  return true;
2769  }
2770 
2771  return false;
2772 }
2773 
2774 /*
2775  * Find ObjectProperty structure by class_id.
2776  */
2777 static const ObjectPropertyType *
2779 {
2780  static const ObjectPropertyType *prop_last = NULL;
2781  int index;
2782 
2783  /*
2784  * A shortcut to speed up multiple consecutive lookups of a particular
2785  * object class.
2786  */
2787  if (prop_last && prop_last->class_oid == class_id)
2788  return prop_last;
2789 
2790  for (index = 0; index < lengthof(ObjectProperty); index++)
2791  {
2792  if (ObjectProperty[index].class_oid == class_id)
2793  {
2794  prop_last = &ObjectProperty[index];
2795  return &ObjectProperty[index];
2796  }
2797  }
2798 
2799  ereport(ERROR,
2800  (errmsg_internal("unrecognized class ID: %u", class_id)));
2801 
2802  return NULL; /* keep MSC compiler happy */
2803 }
2804 
2805 /*
2806  * Return a copy of the tuple for the object with the given object OID, from
2807  * the given catalog (which must have been opened by the caller and suitably
2808  * locked). NULL is returned if the OID is not found.
2809  *
2810  * We try a syscache first, if available.
2811  */
2812 HeapTuple
2814 {
2815  HeapTuple tuple;
2816  Oid classId = RelationGetRelid(catalog);
2817  int oidCacheId = get_object_catcache_oid(classId);
2818 
2819  if (oidCacheId > 0)
2820  {
2821  tuple = SearchSysCacheCopy1(oidCacheId, ObjectIdGetDatum(objectId));
2822  if (!HeapTupleIsValid(tuple)) /* should not happen */
2823  return NULL;
2824  }
2825  else
2826  {
2827  Oid oidIndexId = get_object_oid_index(classId);
2828  SysScanDesc scan;
2829  ScanKeyData skey;
2830 
2831  Assert(OidIsValid(oidIndexId));
2832 
2833  ScanKeyInit(&skey,
2834  oidcol,
2835  BTEqualStrategyNumber, F_OIDEQ,
2836  ObjectIdGetDatum(objectId));
2837 
2838  scan = systable_beginscan(catalog, oidIndexId, true,
2839  NULL, 1, &skey);
2840  tuple = systable_getnext(scan);
2841  if (!HeapTupleIsValid(tuple))
2842  {
2843  systable_endscan(scan);
2844  return NULL;
2845  }
2846  tuple = heap_copytuple(tuple);
2847 
2848  systable_endscan(scan);
2849  }
2850 
2851  return tuple;
2852 }
2853 
2854 /*
2855  * getPublicationSchemaInfo
2856  *
2857  * Get publication name and schema name from the object address into pubname and
2858  * nspname. Both pubname and nspname are palloc'd strings which will be freed by
2859  * the caller.
2860  */
2861 static bool
2862 getPublicationSchemaInfo(const ObjectAddress *object, bool missing_ok,
2863  char **pubname, char **nspname)
2864 {
2865  HeapTuple tup;
2867 
2869  ObjectIdGetDatum(object->objectId));
2870  if (!HeapTupleIsValid(tup))
2871  {
2872  if (!missing_ok)
2873  elog(ERROR, "cache lookup failed for publication schema %u",
2874  object->objectId);
2875  return false;
2876  }
2877 
2878  pnform = (Form_pg_publication_namespace) GETSTRUCT(tup);
2879  *pubname = get_publication_name(pnform->pnpubid, missing_ok);
2880  if (!(*pubname))
2881  {
2882  ReleaseSysCache(tup);
2883  return false;
2884  }
2885 
2886  *nspname = get_namespace_name(pnform->pnnspid);
2887  if (!(*nspname))
2888  {
2889  Oid schemaid = pnform->pnnspid;
2890 
2891  pfree(*pubname);
2892  ReleaseSysCache(tup);
2893  if (!missing_ok)
2894  elog(ERROR, "cache lookup failed for schema %u",
2895  schemaid);
2896  return false;
2897  }
2898 
2899  ReleaseSysCache(tup);
2900  return true;
2901 }
2902 
2903 /*
2904  * getObjectDescription: build an object description for messages
2905  *
2906  * The result is a palloc'd string. NULL is returned for an undefined
2907  * object if missing_ok is true, else an error is generated.
2908  */
2909 char *
2910 getObjectDescription(const ObjectAddress *object, bool missing_ok)
2911 {
2912  StringInfoData buffer;
2913 
2914  initStringInfo(&buffer);
2915 
2916  switch (getObjectClass(object))
2917  {
2918  case OCLASS_CLASS:
2919  if (object->objectSubId == 0)
2920  getRelationDescription(&buffer, object->objectId, missing_ok);
2921  else
2922  {
2923  /* column, not whole relation */
2924  StringInfoData rel;
2925  char *attname = get_attname(object->objectId,
2926  object->objectSubId,
2927  missing_ok);
2928 
2929  if (!attname)
2930  break;
2931 
2932  initStringInfo(&rel);
2933  getRelationDescription(&rel, object->objectId, missing_ok);
2934  /* translator: second %s is, e.g., "table %s" */
2935  appendStringInfo(&buffer, _("column %s of %s"),
2936  attname, rel.data);
2937  pfree(rel.data);
2938  }
2939  break;
2940 
2941  case OCLASS_PROC:
2942  {
2944  char *proname = format_procedure_extended(object->objectId,
2945  flags);
2946 
2947  if (proname == NULL)
2948  break;
2949 
2950  appendStringInfo(&buffer, _("function %s"), proname);
2951  break;
2952  }
2953 
2954  case OCLASS_TYPE:
2955  {
2957  char *typname = format_type_extended(object->objectId, -1,
2958  flags);
2959 
2960  if (typname == NULL)
2961  break;
2962 
2963  appendStringInfo(&buffer, _("type %s"), typname);
2964  break;
2965  }
2966 
2967  case OCLASS_CAST:
2968  {
2969  Relation castDesc;
2970  ScanKeyData skey[1];
2971  SysScanDesc rcscan;
2972  HeapTuple tup;
2973  Form_pg_cast castForm;
2974 
2975  castDesc = table_open(CastRelationId, AccessShareLock);
2976 
2977  ScanKeyInit(&skey[0],
2978  Anum_pg_cast_oid,
2979  BTEqualStrategyNumber, F_OIDEQ,
2980  ObjectIdGetDatum(object->objectId));
2981 
2982  rcscan = systable_beginscan(castDesc, CastOidIndexId, true,
2983  NULL, 1, skey);
2984 
2985  tup = systable_getnext(rcscan);
2986 
2987  if (!HeapTupleIsValid(tup))
2988  {
2989  if (!missing_ok)
2990  elog(ERROR, "could not find tuple for cast %u",
2991  object->objectId);
2992 
2993  systable_endscan(rcscan);
2994  table_close(castDesc, AccessShareLock);
2995  break;
2996  }
2997 
2998  castForm = (Form_pg_cast) GETSTRUCT(tup);
2999 
3000  appendStringInfo(&buffer, _("cast from %s to %s"),
3001  format_type_be(castForm->castsource),
3002  format_type_be(castForm->casttarget));
3003 
3004  systable_endscan(rcscan);
3005  table_close(castDesc, AccessShareLock);
3006  break;
3007  }
3008 
3009  case OCLASS_COLLATION:
3010  {
3011  HeapTuple collTup;
3012  Form_pg_collation coll;
3013  char *nspname;
3014 
3015  collTup = SearchSysCache1(COLLOID,
3016  ObjectIdGetDatum(object->objectId));
3017  if (!HeapTupleIsValid(collTup))
3018  {
3019  if (!missing_ok)
3020  elog(ERROR, "cache lookup failed for collation %u",
3021  object->objectId);
3022  break;
3023  }
3024 
3025  coll = (Form_pg_collation) GETSTRUCT(collTup);
3026 
3027  /* Qualify the name if not visible in search path */
3028  if (CollationIsVisible(object->objectId))
3029  nspname = NULL;
3030  else
3031  nspname = get_namespace_name(coll->collnamespace);
3032 
3033  appendStringInfo(&buffer, _("collation %s"),
3035  NameStr(coll->collname)));
3036  ReleaseSysCache(collTup);
3037  break;
3038  }
3039 
3040  case OCLASS_CONSTRAINT:
3041  {
3042  HeapTuple conTup;
3043  Form_pg_constraint con;
3044 
3045  conTup = SearchSysCache1(CONSTROID,
3046  ObjectIdGetDatum(object->objectId));
3047  if (!HeapTupleIsValid(conTup))
3048  {
3049  if (!missing_ok)
3050  elog(ERROR, "cache lookup failed for constraint %u",
3051  object->objectId);
3052  break;
3053  }
3054 
3055  con = (Form_pg_constraint) GETSTRUCT(conTup);
3056 
3057  if (OidIsValid(con->conrelid))
3058  {
3059  StringInfoData rel;
3060 
3061  initStringInfo(&rel);
3062  getRelationDescription(&rel, con->conrelid, false);
3063  /* translator: second %s is, e.g., "table %s" */
3064  appendStringInfo(&buffer, _("constraint %s on %s"),
3065  NameStr(con->conname), rel.data);
3066  pfree(rel.data);
3067  }
3068  else
3069  {
3070  appendStringInfo(&buffer, _("constraint %s"),
3071  NameStr(con->conname));
3072  }
3073 
3074  ReleaseSysCache(conTup);
3075  break;
3076  }
3077 
3078  case OCLASS_CONVERSION:
3079  {
3080  HeapTuple conTup;
3081  Form_pg_conversion conv;
3082  char *nspname;
3083 
3084  conTup = SearchSysCache1(CONVOID,
3085  ObjectIdGetDatum(object->objectId));
3086  if (!HeapTupleIsValid(conTup))
3087  {
3088  if (!missing_ok)
3089  elog(ERROR, "cache lookup failed for conversion %u",
3090  object->objectId);
3091  break;
3092  }
3093 
3094  conv = (Form_pg_conversion) GETSTRUCT(conTup);
3095 
3096  /* Qualify the name if not visible in search path */
3097  if (ConversionIsVisible(object->objectId))
3098  nspname = NULL;
3099  else
3100  nspname = get_namespace_name(conv->connamespace);
3101 
3102  appendStringInfo(&buffer, _("conversion %s"),
3104  NameStr(conv->conname)));
3105  ReleaseSysCache(conTup);
3106  break;
3107  }
3108 
3109  case OCLASS_DEFAULT:
3110  {
3111  ObjectAddress colobject;
3112 
3113  colobject = GetAttrDefaultColumnAddress(object->objectId);
3114 
3115  if (!OidIsValid(colobject.objectId))
3116  {
3117  if (!missing_ok)
3118  elog(ERROR, "could not find tuple for attrdef %u",
3119  object->objectId);
3120  break;
3121  }
3122 
3123  /* translator: %s is typically "column %s of table %s" */
3124  appendStringInfo(&buffer, _("default value for %s"),
3125  getObjectDescription(&colobject, false));
3126  break;
3127  }
3128 
3129  case OCLASS_LANGUAGE:
3130  {
3131  char *langname = get_language_name(object->objectId,
3132  missing_ok);
3133 
3134  if (langname)
3135  appendStringInfo(&buffer, _("language %s"),
3136  get_language_name(object->objectId, false));
3137  break;
3138  }
3139 
3140  case OCLASS_LARGEOBJECT:
3141  if (!LargeObjectExists(object->objectId))
3142  break;
3143  appendStringInfo(&buffer, _("large object %u"),
3144  object->objectId);
3145  break;
3146 
3147  case OCLASS_OPERATOR:
3148  {
3150  char *oprname = format_operator_extended(object->objectId,
3151  flags);
3152 
3153  if (oprname == NULL)
3154  break;
3155 
3156  appendStringInfo(&buffer, _("operator %s"), oprname);
3157  break;
3158  }
3159 
3160  case OCLASS_OPCLASS:
3161  {
3162  HeapTuple opcTup;
3163  Form_pg_opclass opcForm;
3164  HeapTuple amTup;
3165  Form_pg_am amForm;
3166  char *nspname;
3167 
3168  opcTup = SearchSysCache1(CLAOID,
3169  ObjectIdGetDatum(object->objectId));
3170  if (!HeapTupleIsValid(opcTup))
3171  {
3172  if (!missing_ok)
3173  elog(ERROR, "cache lookup failed for opclass %u",
3174  object->objectId);
3175  break;
3176  }
3177 
3178  opcForm = (Form_pg_opclass) GETSTRUCT(opcTup);
3179 
3180  amTup = SearchSysCache1(AMOID,
3181  ObjectIdGetDatum(opcForm->opcmethod));
3182  if (!HeapTupleIsValid(amTup))
3183  elog(ERROR, "cache lookup failed for access method %u",
3184  opcForm->opcmethod);
3185  amForm = (Form_pg_am) GETSTRUCT(amTup);
3186 
3187  /* Qualify the name if not visible in search path */
3188  if (OpclassIsVisible(object->objectId))
3189  nspname = NULL;
3190  else
3191  nspname = get_namespace_name(opcForm->opcnamespace);
3192 
3193  appendStringInfo(&buffer, _("operator class %s for access method %s"),
3195  NameStr(opcForm->opcname)),
3196  NameStr(amForm->amname));
3197 
3198  ReleaseSysCache(amTup);
3199  ReleaseSysCache(opcTup);
3200  break;
3201  }
3202 
3203  case OCLASS_OPFAMILY:
3204  getOpFamilyDescription(&buffer, object->objectId, missing_ok);
3205  break;
3206 
3207  case OCLASS_AM:
3208  {
3209  HeapTuple tup;
3210 
3211  tup = SearchSysCache1(AMOID,
3212  ObjectIdGetDatum(object->objectId));
3213  if (!HeapTupleIsValid(tup))
3214  {
3215  if (!missing_ok)
3216  elog(ERROR, "cache lookup failed for access method %u",
3217  object->objectId);
3218  break;
3219  }
3220 
3221  appendStringInfo(&buffer, _("access method %s"),
3222  NameStr(((Form_pg_am) GETSTRUCT(tup))->amname));
3223  ReleaseSysCache(tup);
3224  break;
3225  }
3226 
3227  case OCLASS_AMOP:
3228  {
3229  Relation amopDesc;
3230  HeapTuple tup;
3231  ScanKeyData skey[1];
3232  SysScanDesc amscan;
3233  Form_pg_amop amopForm;
3234  StringInfoData opfam;
3235 
3236  amopDesc = table_open(AccessMethodOperatorRelationId,
3237  AccessShareLock);
3238 
3239  ScanKeyInit(&skey[0],
3240  Anum_pg_amop_oid,
3241  BTEqualStrategyNumber, F_OIDEQ,
3242  ObjectIdGetDatum(object->objectId));
3243 
3244  amscan = systable_beginscan(amopDesc, AccessMethodOperatorOidIndexId, true,
3245  NULL, 1, skey);
3246 
3247  tup = systable_getnext(amscan);
3248 
3249  if (!HeapTupleIsValid(tup))
3250  {
3251  if (!missing_ok)
3252  elog(ERROR, "could not find tuple for amop entry %u",
3253  object->objectId);
3254 
3255  systable_endscan(amscan);
3256  table_close(amopDesc, AccessShareLock);
3257  break;
3258  }
3259 
3260  amopForm = (Form_pg_amop) GETSTRUCT(tup);
3261 
3262  initStringInfo(&opfam);
3263  getOpFamilyDescription(&opfam, amopForm->amopfamily, false);
3264 
3265  /*------
3266  translator: %d is the operator strategy (a number), the
3267  first two %s's are data type names, the third %s is the
3268  description of the operator family, and the last %s is the
3269  textual form of the operator with arguments. */
3270  appendStringInfo(&buffer, _("operator %d (%s, %s) of %s: %s"),
3271  amopForm->amopstrategy,
3272  format_type_be(amopForm->amoplefttype),
3273  format_type_be(amopForm->amoprighttype),
3274  opfam.data,
3275  format_operator(amopForm->amopopr));
3276 
3277  pfree(opfam.data);
3278 
3279  systable_endscan(amscan);
3280  table_close(amopDesc, AccessShareLock);
3281  break;
3282  }
3283 
3284  case OCLASS_AMPROC:
3285  {
3286  Relation amprocDesc;
3287  ScanKeyData skey[1];
3288  SysScanDesc amscan;
3289  HeapTuple tup;
3290  Form_pg_amproc amprocForm;
3291  StringInfoData opfam;
3292 
3293  amprocDesc = table_open(AccessMethodProcedureRelationId,
3294  AccessShareLock);
3295 
3296  ScanKeyInit(&skey[0],
3297  Anum_pg_amproc_oid,
3298  BTEqualStrategyNumber, F_OIDEQ,
3299  ObjectIdGetDatum(object->objectId));
3300 
3301  amscan = systable_beginscan(amprocDesc, AccessMethodProcedureOidIndexId, true,
3302  NULL, 1, skey);
3303 
3304  tup = systable_getnext(amscan);
3305 
3306  if (!HeapTupleIsValid(tup))
3307  {
3308  if (!missing_ok)
3309  elog(ERROR, "could not find tuple for amproc entry %u",
3310  object->objectId);
3311 
3312  systable_endscan(amscan);
3313  table_close(amprocDesc, AccessShareLock);
3314  break;
3315  }
3316 
3317  amprocForm = (Form_pg_amproc) GETSTRUCT(tup);
3318 
3319  initStringInfo(&opfam);
3320  getOpFamilyDescription(&opfam, amprocForm->amprocfamily, false);
3321 
3322  /*------
3323  translator: %d is the function number, the first two %s's
3324  are data type names, the third %s is the description of the
3325  operator family, and the last %s is the textual form of the
3326  function with arguments. */
3327  appendStringInfo(&buffer, _("function %d (%s, %s) of %s: %s"),
3328  amprocForm->amprocnum,
3329  format_type_be(amprocForm->amproclefttype),
3330  format_type_be(amprocForm->amprocrighttype),
3331  opfam.data,
3332  format_procedure(amprocForm->amproc));
3333 
3334  pfree(opfam.data);
3335 
3336  systable_endscan(amscan);
3337  table_close(amprocDesc, AccessShareLock);
3338  break;
3339  }
3340 
3341  case OCLASS_REWRITE:
3342  {
3343  Relation ruleDesc;
3344  ScanKeyData skey[1];
3345  SysScanDesc rcscan;
3346  HeapTuple tup;
3348  StringInfoData rel;
3349 
3350  ruleDesc = table_open(RewriteRelationId, AccessShareLock);
3351 
3352  ScanKeyInit(&skey[0],
3353  Anum_pg_rewrite_oid,
3354  BTEqualStrategyNumber, F_OIDEQ,
3355  ObjectIdGetDatum(object->objectId));
3356 
3357  rcscan = systable_beginscan(ruleDesc, RewriteOidIndexId, true,
3358  NULL, 1, skey);
3359 
3360  tup = systable_getnext(rcscan);
3361 
3362  if (!HeapTupleIsValid(tup))
3363  {
3364  if (!missing_ok)
3365  elog(ERROR, "could not find tuple for rule %u",
3366  object->objectId);
3367 
3368  systable_endscan(rcscan);
3369  table_close(ruleDesc, AccessShareLock);
3370  break;
3371  }
3372 
3373  rule = (Form_pg_rewrite) GETSTRUCT(tup);
3374 
3375  initStringInfo(&rel);
3376  getRelationDescription(&rel, rule->ev_class, false);
3377 
3378  /* translator: second %s is, e.g., "table %s" */
3379  appendStringInfo(&buffer, _("rule %s on %s"),
3380  NameStr(rule->rulename), rel.data);
3381  pfree(rel.data);
3382  systable_endscan(rcscan);
3383  table_close(ruleDesc, AccessShareLock);
3384  break;
3385  }
3386 
3387  case OCLASS_TRIGGER:
3388  {
3389  Relation trigDesc;
3390  ScanKeyData skey[1];
3391  SysScanDesc tgscan;
3392  HeapTuple tup;
3393  Form_pg_trigger trig;
3394  StringInfoData rel;
3395 
3396  trigDesc = table_open(TriggerRelationId, AccessShareLock);
3397 
3398  ScanKeyInit(&skey[0],
3399  Anum_pg_trigger_oid,
3400  BTEqualStrategyNumber, F_OIDEQ,
3401  ObjectIdGetDatum(object->objectId));
3402 
3403  tgscan = systable_beginscan(trigDesc, TriggerOidIndexId, true,
3404  NULL, 1, skey);
3405 
3406  tup = systable_getnext(tgscan);
3407 
3408  if (!HeapTupleIsValid(tup))
3409  {
3410  if (!missing_ok)
3411  elog(ERROR, "could not find tuple for trigger %u",
3412  object->objectId);
3413 
3414  systable_endscan(tgscan);
3415  table_close(trigDesc, AccessShareLock);
3416  break;
3417  }
3418 
3419  trig = (Form_pg_trigger) GETSTRUCT(tup);
3420 
3421  initStringInfo(&rel);
3422  getRelationDescription(&rel, trig->tgrelid, false);
3423 
3424  /* translator: second %s is, e.g., "table %s" */
3425  appendStringInfo(&buffer, _("trigger %s on %s"),
3426  NameStr(trig->tgname), rel.data);
3427  pfree(rel.data);
3428  systable_endscan(tgscan);
3429  table_close(trigDesc, AccessShareLock);
3430  break;
3431  }
3432 
3433  case OCLASS_SCHEMA:
3434  {
3435  char *nspname;
3436 
3437  nspname = get_namespace_name(object->objectId);
3438  if (!nspname)
3439  {
3440  if (!missing_ok)
3441  elog(ERROR, "cache lookup failed for namespace %u",
3442  object->objectId);
3443  break;
3444  }
3445  appendStringInfo(&buffer, _("schema %s"), nspname);
3446  break;
3447  }
3448 
3449  case OCLASS_STATISTIC_EXT:
3450  {
3451  HeapTuple stxTup;
3452  Form_pg_statistic_ext stxForm;
3453  char *nspname;
3454 
3455  stxTup = SearchSysCache1(STATEXTOID,
3456  ObjectIdGetDatum(object->objectId));
3457  if (!HeapTupleIsValid(stxTup))
3458  {
3459  if (!missing_ok)
3460  elog(ERROR, "could not find tuple for statistics object %u",
3461  object->objectId);
3462  break;
3463  }
3464 
3465  stxForm = (Form_pg_statistic_ext) GETSTRUCT(stxTup);
3466 
3467  /* Qualify the name if not visible in search path */
3468  if (StatisticsObjIsVisible(object->objectId))
3469  nspname = NULL;
3470  else
3471  nspname = get_namespace_name(stxForm->stxnamespace);
3472 
3473  appendStringInfo(&buffer, _("statistics object %s"),
3475  NameStr(stxForm->stxname)));
3476 
3477  ReleaseSysCache(stxTup);
3478  break;
3479  }
3480 
3481  case OCLASS_TSPARSER:
3482  {
3483  HeapTuple tup;
3484  Form_pg_ts_parser prsForm;
3485  char *nspname;
3486 
3488  ObjectIdGetDatum(object->objectId));
3489  if (!HeapTupleIsValid(tup))
3490  {
3491  if (!missing_ok)
3492  elog(ERROR, "cache lookup failed for text search parser %u",
3493  object->objectId);
3494  break;
3495  }
3496  prsForm = (Form_pg_ts_parser) GETSTRUCT(tup);
3497 
3498  /* Qualify the name if not visible in search path */
3499  if (TSParserIsVisible(object->objectId))
3500  nspname = NULL;
3501  else
3502  nspname = get_namespace_name(prsForm->prsnamespace);
3503 
3504  appendStringInfo(&buffer, _("text search parser %s"),
3506  NameStr(prsForm->prsname)));
3507  ReleaseSysCache(tup);
3508  break;
3509  }
3510 
3511  case OCLASS_TSDICT:
3512  {
3513  HeapTuple tup;
3514  Form_pg_ts_dict dictForm;
3515  char *nspname;
3516 
3517  tup = SearchSysCache1(TSDICTOID,
3518  ObjectIdGetDatum(object->objectId));
3519  if (!HeapTupleIsValid(tup))
3520  {
3521  if (!missing_ok)
3522  elog(ERROR, "cache lookup failed for text search dictionary %u",
3523  object->objectId);
3524  break;
3525  }
3526 
3527  dictForm = (Form_pg_ts_dict) GETSTRUCT(tup);
3528 
3529  /* Qualify the name if not visible in search path */
3530  if (TSDictionaryIsVisible(object->objectId))
3531  nspname = NULL;
3532  else
3533  nspname = get_namespace_name(dictForm->dictnamespace);
3534 
3535  appendStringInfo(&buffer, _("text search dictionary %s"),
3537  NameStr(dictForm->dictname)));
3538  ReleaseSysCache(tup);
3539  break;
3540  }
3541 
3542  case OCLASS_TSTEMPLATE:
3543  {
3544  HeapTuple tup;
3545  Form_pg_ts_template tmplForm;
3546  char *nspname;
3547 
3549  ObjectIdGetDatum(object->objectId));
3550  if (!HeapTupleIsValid(tup))
3551  {
3552  if (!missing_ok)
3553  elog(ERROR, "cache lookup failed for text search template %u",
3554  object->objectId);
3555  break;
3556  }
3557 
3558  tmplForm = (Form_pg_ts_template) GETSTRUCT(tup);
3559 
3560  /* Qualify the name if not visible in search path */
3561  if (TSTemplateIsVisible(object->objectId))
3562  nspname = NULL;
3563  else
3564  nspname = get_namespace_name(tmplForm->tmplnamespace);
3565 
3566  appendStringInfo(&buffer, _("text search template %s"),
3568  NameStr(tmplForm->tmplname)));
3569  ReleaseSysCache(tup);
3570  break;
3571  }
3572 
3573  case OCLASS_TSCONFIG:
3574  {
3575  HeapTuple tup;
3576  Form_pg_ts_config cfgForm;
3577  char *nspname;
3578 
3580  ObjectIdGetDatum(object->objectId));
3581  if (!HeapTupleIsValid(tup))
3582  {
3583  if (!missing_ok)
3584  elog(ERROR, "cache lookup failed for text search configuration %u",
3585  object->objectId);
3586  break;
3587  }
3588 
3589  cfgForm = (Form_pg_ts_config) GETSTRUCT(tup);
3590 
3591  /* Qualify the name if not visible in search path */
3592  if (TSConfigIsVisible(object->objectId))
3593  nspname = NULL;
3594  else
3595  nspname = get_namespace_name(cfgForm->cfgnamespace);
3596 
3597  appendStringInfo(&buffer, _("text search configuration %s"),
3599  NameStr(cfgForm->cfgname)));
3600  ReleaseSysCache(tup);
3601  break;
3602  }
3603 
3604  case OCLASS_ROLE:
3605  {
3606  char *username = GetUserNameFromId(object->objectId,
3607  missing_ok);
3608 
3609  if (username)
3610  appendStringInfo(&buffer, _("role %s"), username);
3611  break;
3612  }
3613 
3615  {
3616  Relation amDesc;
3617  ScanKeyData skey[1];
3618  SysScanDesc rcscan;
3619  HeapTuple tup;
3620  Form_pg_auth_members amForm;
3621 
3622  amDesc = table_open(AuthMemRelationId, AccessShareLock);
3623 
3624  ScanKeyInit(&skey[0],
3625  Anum_pg_auth_members_oid,
3626  BTEqualStrategyNumber, F_OIDEQ,
3627  ObjectIdGetDatum(object->objectId));
3628 
3629  rcscan = systable_beginscan(amDesc, AuthMemOidIndexId, true,
3630  NULL, 1, skey);
3631 
3632  tup = systable_getnext(rcscan);
3633 
3634  if (!HeapTupleIsValid(tup))
3635  {
3636  if (!missing_ok)
3637  elog(ERROR, "could not find tuple for role membership %u",
3638  object->objectId);
3639 
3640  systable_endscan(rcscan);
3641  table_close(amDesc, AccessShareLock);
3642  break;
3643  }
3644 
3645  amForm = (Form_pg_auth_members) GETSTRUCT(tup);
3646 
3647  appendStringInfo(&buffer, _("membership of role %s in role %s"),
3648  GetUserNameFromId(amForm->member, false),
3649  GetUserNameFromId(amForm->roleid, false));
3650 
3651  systable_endscan(rcscan);
3652  table_close(amDesc, AccessShareLock);
3653  break;
3654  }
3655 
3656  case OCLASS_DATABASE:
3657  {
3658  char *datname;
3659 
3660  datname = get_database_name(object->objectId);
3661  if (!datname)
3662  {
3663  if (!missing_ok)
3664  elog(ERROR, "cache lookup failed for database %u",
3665  object->objectId);
3666  break;
3667  }
3668  appendStringInfo(&buffer, _("database %s"), datname);
3669  break;
3670  }
3671 
3672  case OCLASS_TBLSPACE:
3673  {
3674  char *tblspace;
3675 
3676  tblspace = get_tablespace_name(object->objectId);
3677  if (!tblspace)
3678  {
3679  if (!missing_ok)
3680  elog(ERROR, "cache lookup failed for tablespace %u",
3681  object->objectId);
3682  break;
3683  }
3684  appendStringInfo(&buffer, _("tablespace %s"), tblspace);
3685  break;
3686  }
3687 
3688  case OCLASS_FDW:
3689  {
3690  ForeignDataWrapper *fdw;
3691 
3693  missing_ok);
3694  if (fdw)
3695  appendStringInfo(&buffer, _("foreign-data wrapper %s"), fdw->fdwname);
3696  break;
3697  }
3698 
3699  case OCLASS_FOREIGN_SERVER:
3700  {
3701  ForeignServer *srv;
3702 
3703  srv = GetForeignServerExtended(object->objectId, missing_ok);
3704  if (srv)
3705  appendStringInfo(&buffer, _("server %s"), srv->servername);
3706  break;
3707  }
3708 
3709  case OCLASS_USER_MAPPING:
3710  {
3711  HeapTuple tup;
3712  Oid useid;
3713  char *usename;
3714  Form_pg_user_mapping umform;
3715  ForeignServer *srv;
3716 
3718  ObjectIdGetDatum(object->objectId));
3719  if (!HeapTupleIsValid(tup))
3720  {
3721  if (!missing_ok)
3722  elog(ERROR, "cache lookup failed for user mapping %u",
3723  object->objectId);
3724  break;
3725  }
3726 
3727  umform = (Form_pg_user_mapping) GETSTRUCT(tup);
3728  useid = umform->umuser;
3729  srv = GetForeignServer(umform->umserver);
3730 
3731  ReleaseSysCache(tup);
3732 
3733  if (OidIsValid(useid))
3734  usename = GetUserNameFromId(useid, false);
3735  else
3736  usename = "public";
3737 
3738  appendStringInfo(&buffer, _("user mapping for %s on server %s"), usename,
3739  srv->servername);
3740  break;
3741  }
3742 
3743  case OCLASS_DEFACL:
3744  {
3745  Relation defaclrel;
3746  ScanKeyData skey[1];
3747  SysScanDesc rcscan;
3748  HeapTuple tup;
3749  Form_pg_default_acl defacl;
3750  char *rolename;
3751  char *nspname;
3752 
3753  defaclrel = table_open(DefaultAclRelationId, AccessShareLock);
3754 
3755  ScanKeyInit(&skey[0],
3756  Anum_pg_default_acl_oid,
3757  BTEqualStrategyNumber, F_OIDEQ,
3758  ObjectIdGetDatum(object->objectId));
3759 
3760  rcscan = systable_beginscan(defaclrel, DefaultAclOidIndexId,
3761  true, NULL, 1, skey);
3762 
3763  tup = systable_getnext(rcscan);
3764 
3765  if (!HeapTupleIsValid(tup))
3766  {
3767  if (!missing_ok)
3768  elog(ERROR, "could not find tuple for default ACL %u",
3769  object->objectId);
3770 
3771  systable_endscan(rcscan);
3772  table_close(defaclrel, AccessShareLock);
3773  break;
3774  }
3775 
3776  defacl = (Form_pg_default_acl) GETSTRUCT(tup);
3777 
3778  rolename = GetUserNameFromId(defacl->defaclrole, false);
3779 
3780  if (OidIsValid(defacl->defaclnamespace))
3781  nspname = get_namespace_name(defacl->defaclnamespace);
3782  else
3783  nspname = NULL;
3784 
3785  switch (defacl->defaclobjtype)
3786  {
3787  case DEFACLOBJ_RELATION:
3788  if (nspname)
3789  appendStringInfo(&buffer,
3790  _("default privileges on new relations belonging to role %s in schema %s"),
3791  rolename, nspname);
3792  else
3793  appendStringInfo(&buffer,
3794  _("default privileges on new relations belonging to role %s"),
3795  rolename);
3796  break;
3797  case DEFACLOBJ_SEQUENCE:
3798  if (nspname)
3799  appendStringInfo(&buffer,
3800  _("default privileges on new sequences belonging to role %s in schema %s"),
3801  rolename, nspname);
3802  else
3803  appendStringInfo(&buffer,
3804  _("default privileges on new sequences belonging to role %s"),
3805  rolename);
3806  break;
3807  case DEFACLOBJ_FUNCTION:
3808  if (nspname)
3809  appendStringInfo(&buffer,
3810  _("default privileges on new functions belonging to role %s in schema %s"),
3811  rolename, nspname);
3812  else
3813  appendStringInfo(&buffer,
3814  _("default privileges on new functions belonging to role %s"),
3815  rolename);
3816  break;
3817  case DEFACLOBJ_TYPE:
3818  if (nspname)
3819  appendStringInfo(&buffer,
3820  _("default privileges on new types belonging to role %s in schema %s"),
3821  rolename, nspname);
3822  else
3823  appendStringInfo(&buffer,
3824  _("default privileges on new types belonging to role %s"),
3825  rolename);
3826  break;
3827  case DEFACLOBJ_NAMESPACE:
3828  Assert(!nspname);
3829  appendStringInfo(&buffer,
3830  _("default privileges on new schemas belonging to role %s"),
3831  rolename);
3832  break;
3833  default:
3834  /* shouldn't get here */
3835  if (nspname)
3836  appendStringInfo(&buffer,
3837  _("default privileges belonging to role %s in schema %s"),
3838  rolename, nspname);
3839  else
3840  appendStringInfo(&buffer,
3841  _("default privileges belonging to role %s"),
3842  rolename);
3843  break;
3844  }
3845 
3846  systable_endscan(rcscan);
3847  table_close(defaclrel, AccessShareLock);
3848  break;
3849  }
3850 
3851  case OCLASS_EXTENSION:
3852  {
3853  char *extname;
3854 
3855  extname = get_extension_name(object->objectId);
3856  if (!extname)
3857  {
3858  if (!missing_ok)
3859  elog(ERROR, "cache lookup failed for extension %u",
3860  object->objectId);
3861  break;
3862  }
3863  appendStringInfo(&buffer, _("extension %s"), extname);
3864  break;
3865  }
3866 
3867  case OCLASS_EVENT_TRIGGER:
3868  {
3869  HeapTuple tup;
3870 
3872  ObjectIdGetDatum(object->objectId));
3873  if (!HeapTupleIsValid(tup))
3874  {
3875  if (!missing_ok)
3876  elog(ERROR, "cache lookup failed for event trigger %u",
3877  object->objectId);
3878  break;
3879  }
3880  appendStringInfo(&buffer, _("event trigger %s"),
3881  NameStr(((Form_pg_event_trigger) GETSTRUCT(tup))->evtname));
3882  ReleaseSysCache(tup);
3883  break;
3884  }
3885 
3886  case OCLASS_PARAMETER_ACL:
3887  {
3888  HeapTuple tup;
3889  Datum nameDatum;
3890  bool isNull;
3891  char *parname;
3892 
3894  ObjectIdGetDatum(object->objectId));
3895  if (!HeapTupleIsValid(tup))
3896  {
3897  if (!missing_ok)
3898  elog(ERROR, "cache lookup failed for parameter ACL %u",
3899  object->objectId);
3900  break;
3901  }
3902  nameDatum = SysCacheGetAttr(PARAMETERACLOID, tup,
3903  Anum_pg_parameter_acl_parname,
3904  &isNull);
3905  Assert(!isNull);
3906  parname = TextDatumGetCString(nameDatum);
3907  appendStringInfo(&buffer, _("parameter %s"), parname);
3908  ReleaseSysCache(tup);
3909  break;
3910  }
3911 
3912  case OCLASS_POLICY:
3913  {
3914  Relation policy_rel;
3915  ScanKeyData skey[1];
3916  SysScanDesc sscan;
3917  HeapTuple tuple;
3918  Form_pg_policy form_policy;
3919  StringInfoData rel;
3920 
3921  policy_rel = table_open(PolicyRelationId, AccessShareLock);
3922 
3923  ScanKeyInit(&skey[0],
3924  Anum_pg_policy_oid,
3925  BTEqualStrategyNumber, F_OIDEQ,
3926  ObjectIdGetDatum(object->objectId));
3927 
3928  sscan = systable_beginscan(policy_rel, PolicyOidIndexId,
3929  true, NULL, 1, skey);
3930 
3931  tuple = systable_getnext(sscan);
3932 
3933  if (!HeapTupleIsValid(tuple))
3934  {
3935  if (!missing_ok)
3936  elog(ERROR, "could not find tuple for policy %u",
3937  object->objectId);
3938 
3939  systable_endscan(sscan);
3940  table_close(policy_rel, AccessShareLock);
3941  break;
3942  }
3943 
3944  form_policy = (Form_pg_policy) GETSTRUCT(tuple);
3945 
3946  initStringInfo(&rel);
3947  getRelationDescription(&rel, form_policy->polrelid, false);
3948 
3949  /* translator: second %s is, e.g., "table %s" */
3950  appendStringInfo(&buffer, _("policy %s on %s"),
3951  NameStr(form_policy->polname), rel.data);
3952  pfree(rel.data);
3953  systable_endscan(sscan);
3954  table_close(policy_rel, AccessShareLock);
3955  break;
3956  }
3957 
3958  case OCLASS_PUBLICATION:
3959  {
3960  char *pubname = get_publication_name(object->objectId,
3961  missing_ok);
3962 
3963  if (pubname)
3964  appendStringInfo(&buffer, _("publication %s"), pubname);
3965  break;
3966  }
3967 
3969  {
3970  char *pubname;
3971  char *nspname;
3972 
3973  if (!getPublicationSchemaInfo(object, missing_ok,
3974  &pubname, &nspname))
3975  break;
3976 
3977  appendStringInfo(&buffer, _("publication of schema %s in publication %s"),
3978  nspname, pubname);
3979  pfree(pubname);
3980  pfree(nspname);
3981  break;
3982  }
3983 
3985  {
3986  HeapTuple tup;
3987  char *pubname;
3988  Form_pg_publication_rel prform;
3989  StringInfoData rel;
3990 
3992  ObjectIdGetDatum(object->objectId));
3993  if (!HeapTupleIsValid(tup))
3994  {
3995  if (!missing_ok)
3996  elog(ERROR, "cache lookup failed for publication table %u",
3997  object->objectId);
3998  break;
3999  }
4000 
4001  prform = (Form_pg_publication_rel) GETSTRUCT(tup);
4002  pubname = get_publication_name(prform->prpubid, false);
4003 
4004  initStringInfo(&rel);
4005  getRelationDescription(&rel, prform->prrelid, false);
4006 
4007  /* translator: first %s is, e.g., "table %s" */
4008  appendStringInfo(&buffer, _("publication of %s in publication %s"),
4009  rel.data, pubname);
4010  pfree(rel.data);
4011  ReleaseSysCache(tup);
4012  break;
4013  }
4014 
4015  case OCLASS_SUBSCRIPTION:
4016  {
4017  char *subname = get_subscription_name(object->objectId,
4018  missing_ok);
4019 
4020  if (subname)
4021  appendStringInfo(&buffer, _("subscription %s"), subname);
4022  break;
4023  }
4024 
4025  case OCLASS_TRANSFORM:
4026  {
4027  HeapTuple trfTup;
4028  Form_pg_transform trfForm;
4029 
4030  trfTup = SearchSysCache1(TRFOID,
4031  ObjectIdGetDatum(object->objectId));
4032  if (!HeapTupleIsValid(trfTup))
4033  {
4034  if (!missing_ok)
4035  elog(ERROR, "could not find tuple for transform %u",
4036  object->objectId);
4037  break;
4038  }
4039 
4040  trfForm = (Form_pg_transform) GETSTRUCT(trfTup);
4041 
4042  appendStringInfo(&buffer, _("transform for %s language %s"),
4043  format_type_be(trfForm->trftype),
4044  get_language_name(trfForm->trflang, false));
4045 
4046  ReleaseSysCache(trfTup);
4047  break;
4048  }
4049 
4050  /*
4051  * There's intentionally no default: case here; we want the
4052  * compiler to warn if a new OCLASS hasn't been handled above.
4053  */
4054  }
4055 
4056  /* an empty buffer is equivalent to no object found */
4057  if (buffer.len == 0)
4058  return NULL;
4059 
4060  return buffer.data;
4061 }
4062 
4063 /*
4064  * getObjectDescriptionOids: as above, except the object is specified by Oids
4065  */
4066 char *
4068 {
4069  ObjectAddress address;
4070 
4071  address.classId = classid;
4072  address.objectId = objid;
4073  address.objectSubId = 0;
4074 
4075  return getObjectDescription(&address, false);
4076 }
4077 
4078 /*
4079  * subroutine for getObjectDescription: describe a relation
4080  *
4081  * The result is appended to "buffer".
4082  */
4083 static void
4084 getRelationDescription(StringInfo buffer, Oid relid, bool missing_ok)
4085 {
4086  HeapTuple relTup;
4087  Form_pg_class relForm;
4088  char *nspname;
4089  char *relname;
4090 
4091  relTup = SearchSysCache1(RELOID,
4092  ObjectIdGetDatum(relid));
4093  if (!HeapTupleIsValid(relTup))
4094  {
4095  if (!missing_ok)
4096  elog(ERROR, "cache lookup failed for relation %u", relid);
4097  return;
4098  }
4099  relForm = (Form_pg_class) GETSTRUCT(relTup);
4100 
4101  /* Qualify the name if not visible in search path */
4102  if (RelationIsVisible(relid))
4103  nspname = NULL;
4104  else
4105  nspname = get_namespace_name(relForm->relnamespace);
4106 
4107  relname = quote_qualified_identifier(nspname, NameStr(relForm->relname));
4108 
4109  switch (relForm->relkind)
4110  {
4111  case RELKIND_RELATION:
4112  case RELKIND_PARTITIONED_TABLE:
4113  appendStringInfo(buffer, _("table %s"),
4114  relname);
4115  break;
4116  case RELKIND_INDEX:
4117  case RELKIND_PARTITIONED_INDEX:
4118  appendStringInfo(buffer, _("index %s"),
4119  relname);
4120  break;
4121  case RELKIND_SEQUENCE:
4122  appendStringInfo(buffer, _("sequence %s"),
4123  relname);
4124  break;
4125  case RELKIND_TOASTVALUE:
4126  appendStringInfo(buffer, _("toast table %s"),
4127  relname);
4128  break;
4129  case RELKIND_VIEW:
4130  appendStringInfo(buffer, _("view %s"),
4131  relname);
4132  break;
4133  case RELKIND_MATVIEW:
4134  appendStringInfo(buffer, _("materialized view %s"),
4135  relname);
4136  break;
4137  case RELKIND_COMPOSITE_TYPE:
4138  appendStringInfo(buffer, _("composite type %s"),
4139  relname);
4140  break;
4141  case RELKIND_FOREIGN_TABLE:
4142  appendStringInfo(buffer, _("foreign table %s"),
4143  relname);
4144  break;
4145  default:
4146  /* shouldn't get here */
4147  appendStringInfo(buffer, _("relation %s"),
4148  relname);
4149  break;
4150  }
4151 
4152  ReleaseSysCache(relTup);
4153 }
4154 
4155 /*
4156  * subroutine for getObjectDescription: describe an operator family
4157  */
4158 static void
4159 getOpFamilyDescription(StringInfo buffer, Oid opfid, bool missing_ok)
4160 {
4161  HeapTuple opfTup;
4162  Form_pg_opfamily opfForm;
4163  HeapTuple amTup;
4164  Form_pg_am amForm;
4165  char *nspname;
4166 
4167  opfTup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfid));
4168  if (!HeapTupleIsValid(opfTup))
4169  {
4170  if (!missing_ok)
4171  elog(ERROR, "cache lookup failed for opfamily %u", opfid);
4172  return;
4173  }
4174  opfForm = (Form_pg_opfamily) GETSTRUCT(opfTup);
4175 
4176  amTup = SearchSysCache1(AMOID, ObjectIdGetDatum(opfForm->opfmethod));
4177  if (!HeapTupleIsValid(amTup))
4178  elog(ERROR, "cache lookup failed for access method %u",
4179  opfForm->opfmethod);
4180  amForm = (Form_pg_am) GETSTRUCT(amTup);
4181 
4182  /* Qualify the name if not visible in search path */
4183  if (OpfamilyIsVisible(opfid))
4184  nspname = NULL;
4185  else
4186  nspname = get_namespace_name(opfForm->opfnamespace);
4187 
4188  appendStringInfo(buffer, _("operator family %s for access method %s"),
4190  NameStr(opfForm->opfname)),
4191  NameStr(amForm->amname));
4192 
4193  ReleaseSysCache(amTup);
4194  ReleaseSysCache(opfTup);
4195 }
4196 
4197 /*
4198  * SQL-level callable version of getObjectDescription
4199  */
4200 Datum
4202 {
4203  Oid classid = PG_GETARG_OID(0);
4204  Oid objid = PG_GETARG_OID(1);
4205  int32 objsubid = PG_GETARG_INT32(2);
4206  char *description;
4207  ObjectAddress address;
4208 
4209  /* for "pinned" items in pg_depend, return null */
4210  if (!OidIsValid(classid) && !OidIsValid(objid))
4211  PG_RETURN_NULL();
4212 
4213  address.classId = classid;
4214  address.objectId = objid;
4215  address.objectSubId = objsubid;
4216 
4217  description = getObjectDescription(&address, true);
4218 
4219  if (description == NULL)
4220  PG_RETURN_NULL();
4221 
4222  PG_RETURN_TEXT_P(cstring_to_text(description));
4223 }
4224 
4225 /*
4226  * SQL-level callable function to obtain object type + identity
4227  */
4228 Datum
4230 {
4231  Oid classid = PG_GETARG_OID(0);
4232  Oid objid = PG_GETARG_OID(1);
4233  int32 objsubid = PG_GETARG_INT32(2);
4234  Oid schema_oid = InvalidOid;
4235  const char *objname = NULL;
4236  char *objidentity;
4237  ObjectAddress address;
4238  Datum values[4];
4239  bool nulls[4];
4240  TupleDesc tupdesc;
4241  HeapTuple htup;
4242 
4243  address.classId = classid;
4244  address.objectId = objid;
4245  address.objectSubId = objsubid;
4246 
4247  /*
4248  * Construct a tuple descriptor for the result row. This must match this
4249  * function's pg_proc entry!
4250  */
4251  tupdesc = CreateTemplateTupleDesc(4);
4252  TupleDescInitEntry(tupdesc, (AttrNumber) 1, "type",
4253  TEXTOID, -1, 0);
4254  TupleDescInitEntry(tupdesc, (AttrNumber) 2, "schema",
4255  TEXTOID, -1, 0);
4256  TupleDescInitEntry(tupdesc, (AttrNumber) 3, "name",
4257  TEXTOID, -1, 0);
4258  TupleDescInitEntry(tupdesc, (AttrNumber) 4, "identity",
4259  TEXTOID, -1, 0);
4260 
4261  tupdesc = BlessTupleDesc(tupdesc);
4262 
4263  if (is_objectclass_supported(address.classId))
4264  {
4265  HeapTuple objtup;
4266  Relation catalog = table_open(address.classId, AccessShareLock);
4267 
4268  objtup = get_catalog_object_by_oid(catalog,
4269  get_object_attnum_oid(address.classId),
4270  address.objectId);
4271  if (objtup != NULL)
4272  {
4273  bool isnull;
4274  AttrNumber nspAttnum;
4275  AttrNumber nameAttnum;
4276 
4277  nspAttnum = get_object_attnum_namespace(address.classId);
4278  if (nspAttnum != InvalidAttrNumber)
4279  {
4280  schema_oid = heap_getattr(objtup, nspAttnum,
4281  RelationGetDescr(catalog), &isnull);
4282  if (isnull)
4283  elog(ERROR, "invalid null namespace in object %u/%u/%d",
4284  address.classId, address.objectId, address.objectSubId);
4285  }
4286 
4287  /*
4288  * We only return the object name if it can be used (together with
4289  * the schema name, if any) as a unique identifier.
4290  */
4291  if (get_object_namensp_unique(address.classId))
4292  {
4293  nameAttnum = get_object_attnum_name(address.classId);
4294  if (nameAttnum != InvalidAttrNumber)
4295  {
4296  Datum nameDatum;
4297 
4298  nameDatum = heap_getattr(objtup, nameAttnum,
4299  RelationGetDescr(catalog), &isnull);
4300  if (isnull)
4301  elog(ERROR, "invalid null name in object %u/%u/%d",
4302  address.classId, address.objectId, address.objectSubId);
4303  objname = quote_identifier(NameStr(*(DatumGetName(nameDatum))));
4304  }
4305  }
4306  }
4307 
4308  table_close(catalog, AccessShareLock);
4309  }
4310 
4311  /* object type, which can never be NULL */
4312  values[0] = CStringGetTextDatum(getObjectTypeDescription(&address, true));
4313  nulls[0] = false;
4314 
4315  /*
4316  * Before doing anything, extract the object identity. If the identity
4317  * could not be found, set all the fields except the object type to NULL.
4318  */
4319  objidentity = getObjectIdentity(&address, true);
4320 
4321  /* schema name */
4322  if (OidIsValid(schema_oid) && objidentity)
4323  {
4324  const char *schema = quote_identifier(get_namespace_name(schema_oid));
4325 
4326  values[1] = CStringGetTextDatum(schema);
4327  nulls[1] = false;
4328  }
4329  else
4330  nulls[1] = true;
4331 
4332  /* object name */
4333  if (objname && objidentity)
4334  {
4335  values[2] = CStringGetTextDatum(objname);
4336  nulls[2] = false;
4337  }
4338  else
4339  nulls[2] = true;
4340 
4341  /* object identity */
4342  if (objidentity)
4343  {
4344  values[3] = CStringGetTextDatum(objidentity);
4345  nulls[3] = false;
4346  }
4347  else
4348  nulls[3] = true;
4349 
4350  htup = heap_form_tuple(tupdesc, values, nulls);
4351 
4353 }
4354 
4355 /*
4356  * SQL-level callable function to obtain object type + identity
4357  */
4358 Datum
4360 {
4361  Oid classid = PG_GETARG_OID(0);
4362  Oid objid = PG_GETARG_OID(1);
4363  int32 objsubid = PG_GETARG_INT32(2);
4364  ObjectAddress address;
4365  char *identity;
4366  List *names;
4367  List *args;
4368  Datum values[3];
4369  bool nulls[3];
4370  TupleDesc tupdesc;
4371  HeapTuple htup;
4372 
4373  address.classId = classid;
4374  address.objectId = objid;
4375  address.objectSubId = objsubid;
4376 
4377  /*
4378  * Construct a tuple descriptor for the result row. This must match this
4379  * function's pg_proc entry!
4380  */
4381  tupdesc = CreateTemplateTupleDesc(3);
4382  TupleDescInitEntry(tupdesc, (AttrNumber) 1, "type",
4383  TEXTOID, -1, 0);
4384  TupleDescInitEntry(tupdesc, (AttrNumber) 2, "object_names",
4385  TEXTARRAYOID, -1, 0);
4386  TupleDescInitEntry(tupdesc, (AttrNumber) 3, "object_args",
4387  TEXTARRAYOID, -1, 0);
4388 
4389  tupdesc = BlessTupleDesc(tupdesc);
4390 
4391  /* object type, which can never be NULL */
4392  values[0] = CStringGetTextDatum(getObjectTypeDescription(&address, true));
4393  nulls[0] = false;
4394 
4395  /* object identity */
4396  identity = getObjectIdentityParts(&address, &names, &args, true);
4397  if (identity == NULL)
4398  {
4399  nulls[1] = true;
4400  nulls[2] = true;
4401  }
4402  else
4403  {
4404  pfree(identity);
4405 
4406  /* object_names */
4407  if (names != NIL)
4409  else
4411  nulls[1] = false;
4412 
4413  /* object_args */
4414  if (args)
4416  else
4418  nulls[2] = false;
4419  }
4420 
4421  htup = heap_form_tuple(tupdesc, values, nulls);
4422 
4424 }
4425 
4426 /*
4427  * Return a palloc'ed string that describes the type of object that the
4428  * passed address is for.
4429  *
4430  * Keep ObjectTypeMap in sync with this.
4431  */
4432 char *
4433 getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
4434 {
4435  StringInfoData buffer;
4436 
4437  initStringInfo(&buffer);
4438 
4439  switch (getObjectClass(object))
4440  {
4441  case OCLASS_CLASS:
4442  getRelationTypeDescription(&buffer, object->objectId,
4443  object->objectSubId,
4444  missing_ok);
4445  break;
4446 
4447  case OCLASS_PROC:
4448  getProcedureTypeDescription(&buffer, object->objectId,
4449  missing_ok);
4450  break;
4451 
4452  case OCLASS_TYPE:
4453  appendStringInfoString(&buffer, "type");
4454  break;
4455 
4456  case OCLASS_CAST:
4457  appendStringInfoString(&buffer, "cast");
4458  break;
4459 
4460  case OCLASS_COLLATION:
4461  appendStringInfoString(&buffer, "collation");
4462  break;
4463 
4464  case OCLASS_CONSTRAINT:
4465  getConstraintTypeDescription(&buffer, object->objectId,
4466  missing_ok);
4467  break;
4468 
4469  case OCLASS_CONVERSION:
4470  appendStringInfoString(&buffer, "conversion");
4471  break;
4472 
4473  case OCLASS_DEFAULT:
4474  appendStringInfoString(&buffer, "default value");
4475  break;
4476 
4477  case OCLASS_LANGUAGE:
4478  appendStringInfoString(&buffer, "language");
4479  break;
4480 
4481  case OCLASS_LARGEOBJECT:
4482  appendStringInfoString(&buffer, "large object");
4483  break;
4484 
4485  case OCLASS_OPERATOR:
4486  appendStringInfoString(&buffer, "operator");
4487  break;
4488 
4489  case OCLASS_OPCLASS:
4490  appendStringInfoString(&buffer, "operator class");
4491  break;
4492 
4493  case OCLASS_OPFAMILY:
4494  appendStringInfoString(&buffer, "operator family");
4495  break;
4496 
4497  case OCLASS_AM:
4498  appendStringInfoString(&buffer, "access method");
4499  break;
4500 
4501  case OCLASS_AMOP:
4502  appendStringInfoString(&buffer, "operator of access method");
4503  break;
4504 
4505  case OCLASS_AMPROC:
4506  appendStringInfoString(&buffer, "function of access method");
4507  break;
4508 
4509  case OCLASS_REWRITE:
4510  appendStringInfoString(&buffer, "rule");
4511  break;
4512 
4513  case OCLASS_TRIGGER:
4514  appendStringInfoString(&buffer, "trigger");
4515  break;
4516 
4517  case OCLASS_SCHEMA:
4518  appendStringInfoString(&buffer, "schema");
4519  break;
4520 
4521  case OCLASS_STATISTIC_EXT:
4522  appendStringInfoString(&buffer, "statistics object");
4523  break;
4524 
4525  case OCLASS_TSPARSER:
4526  appendStringInfoString(&buffer, "text search parser");
4527  break;
4528 
4529  case OCLASS_TSDICT:
4530  appendStringInfoString(&buffer, "text search dictionary");
4531  break;
4532 
4533  case OCLASS_TSTEMPLATE:
4534  appendStringInfoString(&buffer, "text search template");
4535  break;
4536 
4537  case OCLASS_TSCONFIG:
4538  appendStringInfoString(&buffer, "text search configuration");
4539  break;
4540 
4541  case OCLASS_ROLE:
4542  appendStringInfoString(&buffer, "role");
4543  break;
4544 
4546  appendStringInfoString(&buffer, "role membership");
4547  break;
4548 
4549  case OCLASS_DATABASE:
4550  appendStringInfoString(&buffer, "database");
4551  break;
4552 
4553  case OCLASS_TBLSPACE:
4554  appendStringInfoString(&buffer, "tablespace");
4555  break;
4556 
4557  case OCLASS_FDW:
4558  appendStringInfoString(&buffer, "foreign-data wrapper");
4559  break;
4560 
4561  case OCLASS_FOREIGN_SERVER:
4562  appendStringInfoString(&buffer, "server");
4563  break;
4564 
4565  case OCLASS_USER_MAPPING:
4566  appendStringInfoString(&buffer, "user mapping");
4567  break;
4568 
4569  case OCLASS_DEFACL:
4570  appendStringInfoString(&buffer, "default acl");
4571  break;
4572 
4573  case OCLASS_EXTENSION:
4574  appendStringInfoString(&buffer, "extension");
4575  break;
4576 
4577  case OCLASS_EVENT_TRIGGER:
4578  appendStringInfoString(&buffer, "event trigger");
4579  break;
4580 
4581  case OCLASS_PARAMETER_ACL:
4582  appendStringInfoString(&buffer, "parameter ACL");
4583  break;
4584 
4585  case OCLASS_POLICY:
4586  appendStringInfoString(&buffer, "policy");
4587  break;
4588 
4589  case OCLASS_PUBLICATION:
4590  appendStringInfoString(&buffer, "publication");
4591  break;
4592 
4594  appendStringInfoString(&buffer, "publication namespace");
4595  break;
4596 
4598  appendStringInfoString(&buffer, "publication relation");
4599  break;
4600 
4601  case OCLASS_SUBSCRIPTION:
4602  appendStringInfoString(&buffer, "subscription");
4603  break;
4604 
4605  case OCLASS_TRANSFORM:
4606  appendStringInfoString(&buffer, "transform");
4607  break;
4608 
4609  /*
4610  * There's intentionally no default: case here; we want the
4611  * compiler to warn if a new OCLASS hasn't been handled above.
4612  */
4613  }
4614 
4615  /* the result can never be empty */
4616  Assert(buffer.len > 0);
4617 
4618  return buffer.data;
4619 }
4620 
4621 /*
4622  * subroutine for getObjectTypeDescription: describe a relation type
4623  */
4624 static void
4625 getRelationTypeDescription(StringInfo buffer, Oid relid, int32 objectSubId,
4626  bool missing_ok)
4627 {
4628  HeapTuple relTup;
4629  Form_pg_class relForm;
4630 
4631  relTup = SearchSysCache1(RELOID,
4632  ObjectIdGetDatum(relid));
4633  if (!HeapTupleIsValid(relTup))
4634  {
4635  if (!missing_ok)
4636  elog(ERROR, "cache lookup failed for relation %u", relid);
4637 
4638  /* fallback to "relation" for an undefined object */
4639  appendStringInfoString(buffer, "relation");
4640  return;
4641  }
4642  relForm = (Form_pg_class) GETSTRUCT(relTup);
4643 
4644  switch (relForm->relkind)
4645  {
4646  case RELKIND_RELATION:
4647  case RELKIND_PARTITIONED_TABLE:
4648  appendStringInfoString(buffer, "table");
4649  break;
4650  case RELKIND_INDEX:
4651  case RELKIND_PARTITIONED_INDEX:
4652  appendStringInfoString(buffer, "index");
4653  break;
4654  case RELKIND_SEQUENCE:
4655  appendStringInfoString(buffer, "sequence");
4656  break;
4657  case RELKIND_TOASTVALUE:
4658  appendStringInfoString(buffer, "toast table");
4659  break;
4660  case RELKIND_VIEW:
4661  appendStringInfoString(buffer, "view");
4662  break;
4663  case RELKIND_MATVIEW:
4664  appendStringInfoString(buffer, "materialized view");
4665  break;
4666  case RELKIND_COMPOSITE_TYPE:
4667  appendStringInfoString(buffer, "composite type");
4668  break;
4669  case RELKIND_FOREIGN_TABLE:
4670  appendStringInfoString(buffer, "foreign table");
4671  break;
4672  default:
4673  /* shouldn't get here */
4674  appendStringInfoString(buffer, "relation");
4675  break;
4676  }
4677 
4678  if (objectSubId != 0)
4679  appendStringInfoString(buffer, " column");
4680 
4681  ReleaseSysCache(relTup);
4682 }
4683 
4684 /*
4685  * subroutine for getObjectTypeDescription: describe a constraint type
4686  */
4687 static void
4688 getConstraintTypeDescription(StringInfo buffer, Oid constroid, bool missing_ok)
4689 {
4690  Relation constrRel;
4691  HeapTuple constrTup;
4692  Form_pg_constraint constrForm;
4693 
4694  constrRel = table_open(ConstraintRelationId, AccessShareLock);
4695  constrTup = get_catalog_object_by_oid(constrRel, Anum_pg_constraint_oid,
4696  constroid);
4697  if (!HeapTupleIsValid(constrTup))
4698  {
4699  if (!missing_ok)
4700  elog(ERROR, "cache lookup failed for constraint %u", constroid);
4701 
4702  table_close(constrRel, AccessShareLock);
4703 
4704  /* fallback to "constraint" for an undefined object */
4705  appendStringInfoString(buffer, "constraint");
4706  return;
4707  }
4708 
4709  constrForm = (Form_pg_constraint) GETSTRUCT(constrTup);
4710 
4711  if (OidIsValid(constrForm->conrelid))
4712  appendStringInfoString(buffer, "table constraint");
4713  else if (OidIsValid(constrForm->contypid))
4714  appendStringInfoString(buffer, "domain constraint");
4715  else
4716  elog(ERROR, "invalid constraint %u", constrForm->oid);
4717 
4718  table_close(constrRel, AccessShareLock);
4719 }
4720 
4721 /*
4722  * subroutine for getObjectTypeDescription: describe a procedure type
4723  */
4724 static void
4726  bool missing_ok)
4727 {
4728  HeapTuple procTup;
4729  Form_pg_proc procForm;
4730 
4731  procTup = SearchSysCache1(PROCOID,
4732  ObjectIdGetDatum(procid));
4733  if (!HeapTupleIsValid(procTup))
4734  {
4735  if (!missing_ok)
4736  elog(ERROR, "cache lookup failed for procedure %u", procid);
4737 
4738  /* fallback to "procedure" for an undefined object */
4739  appendStringInfoString(buffer, "routine");
4740  return;
4741  }
4742  procForm = (Form_pg_proc) GETSTRUCT(procTup);
4743 
4744  if (procForm->prokind == PROKIND_AGGREGATE)
4745  appendStringInfoString(buffer, "aggregate");
4746  else if (procForm->prokind == PROKIND_PROCEDURE)
4747  appendStringInfoString(buffer, "procedure");
4748  else /* function or window function */
4749  appendStringInfoString(buffer, "function");
4750 
4751  ReleaseSysCache(procTup);
4752 }
4753 
4754 /*
4755  * Obtain a given object's identity, as a palloc'ed string.
4756  *
4757  * This is for machine consumption, so it's not translated. All elements are
4758  * schema-qualified when appropriate. Returns NULL if the object could not
4759  * be found.
4760  */
4761 char *
4762 getObjectIdentity(const ObjectAddress *object, bool missing_ok)
4763 {
4764  return getObjectIdentityParts(object, NULL, NULL, missing_ok);
4765 }
4766 
4767 /*
4768  * As above, but more detailed.
4769  *
4770  * There are two sets of return values: the identity itself as a palloc'd
4771  * string is returned. objname and objargs, if not NULL, are output parameters
4772  * that receive lists of C-strings that are useful to give back to
4773  * get_object_address() to reconstruct the ObjectAddress. Returns NULL if
4774  * the object could not be found.
4775  */
4776 char *
4778  List **objname, List **objargs,
4779  bool missing_ok)
4780 {
4781  StringInfoData buffer;
4782 
4783  initStringInfo(&buffer);
4784 
4785  /*
4786  * Make sure that both objname and objargs were passed, or none was; and
4787  * initialize them to empty lists. For objname this is useless because it
4788  * will be initialized in all cases inside the switch; but we do it anyway
4789  * so that we can test below that no branch leaves it unset.
4790  */
4791  Assert(PointerIsValid(objname) == PointerIsValid(objargs));
4792  if (objname)
4793  {
4794  *objname = NIL;
4795  *objargs = NIL;
4796  }
4797 
4798  switch (getObjectClass(object))
4799  {
4800  case OCLASS_CLASS:
4801  {
4802  char *attr = NULL;
4803 
4804  /*
4805  * Check for the attribute first, so as if it is missing we
4806  * can skip the entire relation description.
4807  */
4808  if (object->objectSubId != 0)
4809  {
4810  attr = get_attname(object->objectId,
4811  object->objectSubId,
4812  missing_ok);
4813 
4814  if (missing_ok && attr == NULL)
4815  break;
4816  }
4817 
4818  getRelationIdentity(&buffer, object->objectId, objname,
4819  missing_ok);
4820  if (objname && *objname == NIL)
4821  break;
4822 
4823  if (attr)
4824  {
4825  appendStringInfo(&buffer, ".%s",
4826  quote_identifier(attr));
4827  if (objname)
4828  *objname = lappend(*objname, attr);
4829  }
4830  }
4831  break;
4832 
4833  case OCLASS_PROC:
4834  {
4836  char *proname = format_procedure_extended(object->objectId,
4837  flags);
4838 
4839  if (proname == NULL)
4840  break;
4841 
4842  appendStringInfoString(&buffer, proname);
4843  if (objname)
4844  format_procedure_parts(object->objectId, objname, objargs,
4845  missing_ok);
4846  break;
4847  }
4848 
4849  case OCLASS_TYPE:
4850  {
4852  char *typeout;
4853 
4854  typeout = format_type_extended(object->objectId, -1, flags);
4855 
4856  if (typeout == NULL)
4857  break;
4858 
4859  appendStringInfoString(&buffer, typeout);
4860  if (objname)
4861  *objname = list_make1(typeout);
4862  }
4863  break;
4864 
4865  case OCLASS_CAST:
4866  {
4867  Relation castRel;
4868  HeapTuple tup;
4869  Form_pg_cast castForm;
4870 
4871  castRel = table_open(CastRelationId, AccessShareLock);
4872 
4873  tup = get_catalog_object_by_oid(castRel, Anum_pg_cast_oid,
4874  object->objectId);
4875 
4876  if (!HeapTupleIsValid(tup))
4877  {
4878  if (!missing_ok)
4879  elog(ERROR, "could not find tuple for cast %u",
4880  object->objectId);
4881 
4882  table_close(castRel, AccessShareLock);
4883  break;
4884  }
4885 
4886  castForm = (Form_pg_cast) GETSTRUCT(tup);
4887 
4888  appendStringInfo(&buffer, "(%s AS %s)",
4889  format_type_be_qualified(castForm->castsource),
4890  format_type_be_qualified(castForm->casttarget));
4891 
4892  if (objname)
4893  {
4894  *objname = list_make1(format_type_be_qualified(castForm->castsource));
4895  *objargs = list_make1(format_type_be_qualified(castForm->casttarget));
4896  }
4897 
4898  table_close(castRel, AccessShareLock);
4899  break;
4900  }
4901 
4902  case OCLASS_COLLATION:
4903  {
4904  HeapTuple collTup;
4905  Form_pg_collation coll;
4906  char *schema;
4907 
4908  collTup = SearchSysCache1(COLLOID,
4909  ObjectIdGetDatum(object->objectId));
4910  if (!HeapTupleIsValid(collTup))
4911  {
4912  if (!missing_ok)
4913  elog(ERROR, "cache lookup failed for collation %u",
4914  object->objectId);
4915  break;
4916  }
4917  coll = (Form_pg_collation) GETSTRUCT(collTup);
4918  schema = get_namespace_name_or_temp(coll->collnamespace);
4919  appendStringInfoString(&buffer,
4921  NameStr(coll->collname)));
4922  if (objname)
4923  *objname = list_make2(schema,
4924  pstrdup(NameStr(coll->collname)));
4925  ReleaseSysCache(collTup);
4926  break;
4927  }
4928 
4929  case OCLASS_CONSTRAINT:
4930  {
4931  HeapTuple conTup;
4932  Form_pg_constraint con;
4933 
4934  conTup = SearchSysCache1(CONSTROID,
4935  ObjectIdGetDatum(object->objectId));
4936  if (!HeapTupleIsValid(conTup))
4937  {
4938  if (!missing_ok)
4939  elog(ERROR, "cache lookup failed for constraint %u",
4940  object->objectId);
4941  break;
4942  }
4943  con = (Form_pg_constraint) GETSTRUCT(conTup);
4944 
4945  if (OidIsValid(con->conrelid))
4946  {
4947  appendStringInfo(&buffer, "%s on ",
4948  quote_identifier(NameStr(con->conname)));
4949  getRelationIdentity(&buffer, con->conrelid, objname,
4950  false);
4951  if (objname)
4952  *objname = lappend(*objname, pstrdup(NameStr(con->conname)));
4953  }
4954  else
4955  {
4956  ObjectAddress domain;
4957 
4958  Assert(OidIsValid(con->contypid));
4959  domain.classId = TypeRelationId;
4960  domain.objectId = con->contypid;
4961  domain.objectSubId = 0;
4962 
4963  appendStringInfo(&buffer, "%s on %s",
4964  quote_identifier(NameStr(con->conname)),
4965  getObjectIdentityParts(&domain, objname,
4966  objargs, false));
4967 
4968  if (objname)
4969  *objargs = lappend(*objargs, pstrdup(NameStr(con->conname)));
4970  }
4971 
4972  ReleaseSysCache(conTup);
4973  break;
4974  }
4975 
4976  case OCLASS_CONVERSION:
4977  {
4978  HeapTuple conTup;
4979  Form_pg_conversion conForm;
4980  char *schema;
4981 
4982  conTup = SearchSysCache1(CONVOID,
4983  ObjectIdGetDatum(object->objectId));
4984  if (!HeapTupleIsValid(conTup))
4985  {
4986  if (!missing_ok)
4987  elog(ERROR, "cache lookup failed for conversion %u",
4988  object->objectId);
4989  break;
4990  }
4991  conForm = (Form_pg_conversion) GETSTRUCT(conTup);
4992  schema = get_namespace_name_or_temp(conForm->connamespace);
4993  appendStringInfoString(&buffer,
4995  NameStr(conForm->conname)));
4996  if (objname)
4997  *objname = list_make2(schema,
4998  pstrdup(NameStr(conForm->conname)));
4999  ReleaseSysCache(conTup);
5000  break;
5001  }
5002 
5003  case OCLASS_DEFAULT:
5004  {
5005  ObjectAddress colobject;
5006 
5007  colobject = GetAttrDefaultColumnAddress(object->objectId);
5008 
5009  if (!OidIsValid(colobject.objectId))
5010  {
5011  if (!missing_ok)
5012  elog(ERROR, "could not find tuple for attrdef %u",
5013  object->objectId);
5014  break;
5015  }
5016 
5017  appendStringInfo(&buffer, "for %s",
5018  getObjectIdentityParts(&colobject,
5019  objname, objargs,
5020  false));
5021  break;
5022  }
5023 
5024  case OCLASS_LANGUAGE:
5025  {
5026  HeapTuple langTup;
5027  Form_pg_language langForm;
5028 
5029  langTup = SearchSysCache1(LANGOID,
5030  ObjectIdGetDatum(object->objectId));
5031  if (!HeapTupleIsValid(langTup))
5032  {
5033  if (!missing_ok)
5034  elog(ERROR, "cache lookup failed for language %u",
5035  object->objectId);
5036  break;
5037  }
5038  langForm = (Form_pg_language) GETSTRUCT(langTup);
5039  appendStringInfoString(&buffer,
5040  quote_identifier(NameStr(langForm->lanname)));
5041  if (objname)
5042  *objname = list_make1(pstrdup(NameStr(langForm->lanname)));
5043  ReleaseSysCache(langTup);
5044  break;
5045  }
5046  case OCLASS_LARGEOBJECT:
5047  if (!LargeObjectExists(object->objectId))
5048  break;
5049  appendStringInfo(&buffer, "%u",
5050  object->objectId);
5051  if (objname)
5052  *objname = list_make1(psprintf("%u", object->objectId));
5053  break;
5054 
5055  case OCLASS_OPERATOR:
5056  {
5058  char *oprname = format_operator_extended(object->objectId,
5059  flags);
5060 
5061  if (oprname == NULL)
5062  break;
5063 
5064  appendStringInfoString(&buffer, oprname);
5065  if (objname)
5066  format_operator_parts(object->objectId, objname, objargs, missing_ok);
5067  break;
5068  }
5069 
5070  case OCLASS_OPCLASS:
5071  {
5072  HeapTuple opcTup;
5073  Form_pg_opclass opcForm;
5074  HeapTuple amTup;
5075  Form_pg_am amForm;
5076  char *schema;
5077 
5078  opcTup = SearchSysCache1(CLAOID,
5079  ObjectIdGetDatum(object->objectId));
5080  if (!HeapTupleIsValid(opcTup))
5081  {
5082  if (!missing_ok)
5083  elog(ERROR, "cache lookup failed for opclass %u",
5084  object->objectId);
5085  break;
5086  }
5087  opcForm = (Form_pg_opclass) GETSTRUCT(opcTup);
5088  schema = get_namespace_name_or_temp(opcForm->opcnamespace);
5089 
5090  amTup = SearchSysCache1(AMOID,
5091  ObjectIdGetDatum(opcForm->opcmethod));
5092  if (!HeapTupleIsValid(amTup))
5093  elog(ERROR, "cache lookup failed for access method %u",
5094  opcForm->opcmethod);
5095  amForm = (Form_pg_am) GETSTRUCT(amTup);
5096 
5097  appendStringInfo(&buffer, "%s USING %s",
5099  NameStr(opcForm->opcname)),
5100  quote_identifier(NameStr(amForm->amname)));
5101  if (objname)
5102  *objname = list_make3(pstrdup(NameStr(amForm->amname)),
5103  schema,
5104  pstrdup(NameStr(opcForm->opcname)));
5105 
5106  ReleaseSysCache(amTup);
5107  ReleaseSysCache(opcTup);
5108  break;
5109  }
5110 
5111  case OCLASS_OPFAMILY:
5112  getOpFamilyIdentity(&buffer, object->objectId, objname,
5113  missing_ok);
5114  break;
5115 
5116  case OCLASS_AM:
5117  {
5118  char *amname;
5119 
5120  amname = get_am_name(object->objectId);
5121  if (!amname)
5122  {
5123  if (!missing_ok)
5124  elog(ERROR, "cache lookup failed for access method %u",
5125  object->objectId);
5126  break;
5127  }
5128  appendStringInfoString(&buffer, quote_identifier(amname));
5129  if (objname)
5130  *objname = list_make1(amname);
5131  }
5132  break;
5133 
5134  case OCLASS_AMOP:
5135  {
5136  Relation amopDesc;
5137  HeapTuple tup;
5138  ScanKeyData skey[1];
5139  SysScanDesc amscan;
5140  Form_pg_amop amopForm;
5141  StringInfoData opfam;
5142  char *ltype;
5143  char *rtype;
5144 
5145  amopDesc = table_open(AccessMethodOperatorRelationId,
5146  AccessShareLock);
5147 
5148  ScanKeyInit(&skey[0],
5149  Anum_pg_amop_oid,
5150  BTEqualStrategyNumber, F_OIDEQ,
5151  ObjectIdGetDatum(object->objectId));
5152 
5153  amscan = systable_beginscan(amopDesc, AccessMethodOperatorOidIndexId, true,
5154  NULL, 1, skey);
5155 
5156  tup = systable_getnext(amscan);
5157 
5158  if (!HeapTupleIsValid(tup))
5159  {
5160  if (!missing_ok)
5161  elog(ERROR, "could not find tuple for amop entry %u",
5162  object->objectId);
5163 
5164  systable_endscan(amscan);
5165  table_close(amopDesc, AccessShareLock);
5166  break;
5167  }
5168 
5169  amopForm = (Form_pg_amop) GETSTRUCT(tup);
5170 
5171  initStringInfo(&opfam);
5172  getOpFamilyIdentity(&opfam, amopForm->amopfamily, objname,
5173  false);
5174 
5175  ltype = format_type_be_qualified(amopForm->amoplefttype);
5176  rtype = format_type_be_qualified(amopForm->amoprighttype);
5177 
5178  if (objname)
5179  {
5180  *objname = lappend(*objname,
5181  psprintf("%d", amopForm->amopstrategy));
5182  *objargs = list_make2(ltype, rtype);
5183  }
5184 
5185  appendStringInfo(&buffer, "operator %d (%s, %s) of %s",
5186  amopForm->amopstrategy,
5187  ltype, rtype, opfam.data);
5188 
5189  pfree(opfam.data);
5190 
5191  systable_endscan(amscan);
5192  table_close(amopDesc, AccessShareLock);
5193  break;
5194  }
5195 
5196  case OCLASS_AMPROC:
5197  {
5198  Relation amprocDesc;
5199  ScanKeyData skey[1];
5200  SysScanDesc amscan;
5201  HeapTuple tup;
5202  Form_pg_amproc amprocForm;
5203  StringInfoData opfam;
5204  char *ltype;
5205  char *rtype;
5206 
5207  amprocDesc = table_open(AccessMethodProcedureRelationId,
5208  AccessShareLock);
5209 
5210  ScanKeyInit(&skey[0],
5211  Anum_pg_amproc_oid,
5212  BTEqualStrategyNumber, F_OIDEQ,
5213  ObjectIdGetDatum(object->objectId));
5214 
5215  amscan = systable_beginscan(amprocDesc, AccessMethodProcedureOidIndexId, true,
5216  NULL, 1, skey);
5217 
5218  tup = systable_getnext(amscan);
5219 
5220  if (!HeapTupleIsValid(tup))
5221  {
5222  if (!missing_ok)
5223  elog(ERROR, "could not find tuple for amproc entry %u",
5224  object->objectId);
5225 
5226  systable_endscan(amscan);
5227  table_close(amprocDesc, AccessShareLock);
5228  break;
5229  }
5230 
5231  amprocForm = (Form_pg_amproc) GETSTRUCT(tup);
5232 
5233  initStringInfo(&opfam);
5234  getOpFamilyIdentity(&opfam, amprocForm->amprocfamily, objname,
5235  false);
5236 
5237  ltype = format_type_be_qualified(amprocForm->amproclefttype);
5238  rtype = format_type_be_qualified(amprocForm->amprocrighttype);
5239 
5240  if (objname)
5241  {
5242  *objname = lappend(*objname,
5243  psprintf("%d", amprocForm->amprocnum));
5244  *objargs = list_make2(ltype, rtype);
5245  }
5246 
5247  appendStringInfo(&buffer, "function %d (%s, %s) of %s",
5248  amprocForm->amprocnum,
5249  ltype, rtype, opfam.data);
5250 
5251  pfree(opfam.data);
5252 
5253  systable_endscan(amscan);
5254  table_close(amprocDesc, AccessShareLock);
5255  break;
5256  }
5257 
5258  case OCLASS_REWRITE:
5259  {
5260  Relation ruleDesc;
5261  HeapTuple tup;
5263 
5264  ruleDesc = table_open(RewriteRelationId, AccessShareLock);
5265 
5266  tup = get_catalog_object_by_oid(ruleDesc, Anum_pg_rewrite_oid,
5267  object->objectId);
5268 
5269  if (!HeapTupleIsValid(tup))
5270  {
5271  if (!missing_ok)
5272  elog(ERROR, "could not find tuple for rule %u",
5273  object->objectId);
5274 
5275  table_close(ruleDesc, AccessShareLock);
5276  break;
5277  }
5278 
5279  rule = (Form_pg_rewrite) GETSTRUCT(tup);
5280 
5281  appendStringInfo(&buffer, "%s on ",
5282  quote_identifier(NameStr(rule->rulename)));
5283  getRelationIdentity(&buffer, rule->ev_class, objname, false);
5284  if (objname)
5285  *objname = lappend(*objname, pstrdup(NameStr(rule->rulename)));
5286 
5287  table_close(ruleDesc, AccessShareLock);
5288  break;
5289  }
5290 
5291  case OCLASS_TRIGGER:
5292  {
5293  Relation trigDesc;
5294  HeapTuple tup;
5295  Form_pg_trigger trig;
5296 
5297  trigDesc = table_open(TriggerRelationId, AccessShareLock);
5298 
5299  tup = get_catalog_object_by_oid(trigDesc, Anum_pg_trigger_oid,
5300  object->objectId);
5301 
5302  if (!HeapTupleIsValid(tup))
5303  {
5304  if (!missing_ok)
5305  elog(ERROR, "could not find tuple for trigger %u",
5306  object->objectId);
5307 
5308  table_close(trigDesc, AccessShareLock);
5309  break;
5310  }
5311 
5312  trig = (Form_pg_trigger) GETSTRUCT(tup);
5313 
5314  appendStringInfo(&buffer, "%s on ",
5315  quote_identifier(NameStr(trig->tgname)));
5316  getRelationIdentity(&buffer, trig->tgrelid, objname, false);
5317  if (objname)
5318  *objname = lappend(*objname, pstrdup(NameStr(trig->tgname)));
5319 
5320  table_close(trigDesc, AccessShareLock);
5321  break;
5322  }
5323 
5324  case OCLASS_SCHEMA:
5325  {
5326  char *nspname;
5327 
5328  nspname = get_namespace_name_or_temp(object->objectId);
5329  if (!nspname)
5330  {
5331  if (!missing_ok)
5332  elog(ERROR, "cache lookup failed for namespace %u",
5333  object->objectId);
5334  break;
5335  }
5336  appendStringInfoString(&buffer,
5337  quote_identifier(nspname));
5338  if (objname)
5339  *objname = list_make1(nspname);
5340  break;
5341  }
5342 
5343  case OCLASS_STATISTIC_EXT:
5344  {
5345  HeapTuple tup;
5346  Form_pg_statistic_ext formStatistic;
5347  char *schema;
5348 
5350  ObjectIdGetDatum(object->objectId));
5351  if (!HeapTupleIsValid(tup))
5352  {
5353  if (!missing_ok)
5354  elog(ERROR, "cache lookup failed for statistics object %u",
5355  object->objectId);
5356  break;
5357  }
5358  formStatistic = (Form_pg_statistic_ext) GETSTRUCT(tup);
5359  schema = get_namespace_name_or_temp(formStatistic->stxnamespace);
5360  appendStringInfoString(&buffer,
5362  NameStr(formStatistic->stxname)));
5363  if (objname)
5364  *objname = list_make2(schema,
5365  pstrdup(NameStr(formStatistic->stxname)));
5366  ReleaseSysCache(tup);
5367  }
5368  break;
5369 
5370  case OCLASS_TSPARSER:
5371  {
5372  HeapTuple tup;
5373  Form_pg_ts_parser formParser;
5374  char *schema;
5375 
5377  ObjectIdGetDatum(object->objectId));
5378  if (!HeapTupleIsValid(tup))
5379  {
5380  if (!missing_ok)
5381  elog(ERROR, "cache lookup failed for text search parser %u",
5382  object->objectId);
5383  break;
5384  }
5385  formParser = (Form_pg_ts_parser) GETSTRUCT(tup);
5386  schema = get_namespace_name_or_temp(formParser->prsnamespace);
5387  appendStringInfoString(&buffer,
5389  NameStr(formParser->prsname)));
5390  if (objname)
5391  *objname = list_make2(schema,
5392  pstrdup(NameStr(formParser->prsname)));
5393  ReleaseSysCache(tup);
5394  break;
5395  }
5396 
5397  case OCLASS_TSDICT:
5398  {
5399  HeapTuple tup;
5400  Form_pg_ts_dict formDict;
5401  char *schema;
5402 
5403  tup = SearchSysCache1(TSDICTOID,
5404  ObjectIdGetDatum(object->objectId));
5405  if (!HeapTupleIsValid(tup))
5406  {
5407  if (!missing_ok)
5408  elog(ERROR, "cache lookup failed for text search dictionary %u",
5409  object->objectId);
5410  break;
5411  }
5412  formDict = (Form_pg_ts_dict) GETSTRUCT(tup);
5413  schema = get_namespace_name_or_temp(formDict->dictnamespace);
5414  appendStringInfoString(&buffer,
5416  NameStr(formDict->dictname)));
5417  if (objname)
5418  *objname = list_make2(schema,
5419  pstrdup(NameStr(formDict->dictname)));
5420  ReleaseSysCache(tup);
5421  break;
5422  }
5423 
5424  case OCLASS_TSTEMPLATE:
5425  {
5426  HeapTuple tup;
5427  Form_pg_ts_template formTmpl;
5428  char *schema;
5429 
5431  ObjectIdGetDatum(object->objectId));
5432  if (!HeapTupleIsValid(tup))
5433  {
5434  if (!missing_ok)
5435  elog(ERROR, "cache lookup failed for text search template %u",
5436  object->objectId);
5437  break;
5438  }
5439  formTmpl = (Form_pg_ts_template) GETSTRUCT(tup);
5440  schema = get_namespace_name_or_temp(formTmpl->tmplnamespace);
5441  appendStringInfoString(&buffer,
5443  NameStr(formTmpl->tmplname)));
5444  if (objname)
5445  *objname = list_make2(schema,
5446  pstrdup(NameStr(formTmpl->tmplname)));
5447  ReleaseSysCache(tup);
5448  break;
5449  }
5450 
5451  case OCLASS_TSCONFIG:
5452  {
5453  HeapTuple tup;
5454  Form_pg_ts_config formCfg;
5455  char *schema;
5456 
5458  ObjectIdGetDatum(object->objectId));
5459  if (!HeapTupleIsValid(tup))
5460  {
5461  if (!missing_ok)
5462  elog(ERROR, "cache lookup failed for text search configuration %u",
5463  object->objectId);
5464  break;
5465  }
5466  formCfg = (Form_pg_ts_config) GETSTRUCT(tup);
5467  schema = get_namespace_name_or_temp(formCfg->cfgnamespace);
5468  appendStringInfoString(&buffer,
5470  NameStr(formCfg->cfgname)));
5471  if (objname)
5472  *objname = list_make2(schema,
5473  pstrdup(NameStr(formCfg->cfgname)));
5474  ReleaseSysCache(tup);
5475  break;
5476  }
5477 
5478  case OCLASS_ROLE:
5479  {
5480  char *username;
5481 
5482  username = GetUserNameFromId(object->objectId, missing_ok);
5483  if (!username)
5484  break;
5485  if (objname)
5486  *objname = list_make1(username);
5487  appendStringInfoString(&buffer,
5489  break;
5490  }
5491 
5493  {
5494  Relation authMemDesc;
5495  ScanKeyData skey[1];
5496  SysScanDesc amscan;
5497  HeapTuple tup;
5498  Form_pg_auth_members amForm;
5499 
5500  authMemDesc = table_open(AuthMemRelationId,
5501  AccessShareLock);
5502 
5503  ScanKeyInit(&skey[0],
5504  Anum_pg_auth_members_oid,
5505  BTEqualStrategyNumber, F_OIDEQ,
5506  ObjectIdGetDatum(object->objectId));
5507 
5508  amscan = systable_beginscan(authMemDesc, AuthMemOidIndexId, true,
5509  NULL, 1, skey);
5510 
5511  tup = systable_getnext(amscan);
5512 
5513  if (!HeapTupleIsValid(tup))
5514  {
5515  if (!missing_ok)
5516  elog(ERROR, "could not find tuple for pg_auth_members entry %u",
5517  object->objectId);
5518 
5519  systable_endscan(amscan);
5520  table_close(authMemDesc, AccessShareLock);
5521  break;
5522  }
5523 
5524  amForm = (Form_pg_auth_members) GETSTRUCT(tup);
5525 
5526  appendStringInfo(&buffer, _("membership of role %s in role %s"),
5527  GetUserNameFromId(amForm->member, false),
5528  GetUserNameFromId(amForm->roleid, false));
5529 
5530  systable_endscan(amscan);
5531  table_close(authMemDesc, AccessShareLock);
5532  break;
5533  }
5534 
5535  case OCLASS_DATABASE:
5536  {
5537  char *datname;
5538 
5539  datname = get_database_name(object->objectId);
5540  if (!datname)
5541  {
5542  if (!missing_ok)
5543  elog(ERROR, "cache lookup failed for database %u",
5544  object->objectId);
5545  break;
5546  }
5547  if (objname)
5548  *objname = list_make1(datname);
5549  appendStringInfoString(&buffer,
5551  break;
5552  }
5553 
5554  case OCLASS_TBLSPACE:
5555  {
5556  char *tblspace;
5557 
5558  tblspace = get_tablespace_name(object->objectId);
5559  if (!tblspace)
5560  {
5561  if (!missing_ok)
5562  elog(ERROR, "cache lookup failed for tablespace %u",
5563  object->objectId);
5564  break;
5565  }
5566  if (objname)
5567  *objname = list_make1(tblspace);
5568  appendStringInfoString(&buffer,
5569  quote_identifier(tblspace));
5570  break;