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