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