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