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