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