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