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