PostgreSQL Source Code  git master
objectaddress.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * objectaddress.c
4  * functions for working with ObjectAddresses
5  *
6  * Portions Copyright (c) 1996-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 "miscadmin.h"
73 #include "nodes/makefuncs.h"
74 #include "parser/parse_func.h"
75 #include "parser/parse_oper.h"
76 #include "parser/parse_type.h"
77 #include "rewrite/rewriteSupport.h"
78 #include "storage/large_object.h"
79 #include "storage/lmgr.h"
80 #include "storage/sinval.h"
81 #include "utils/builtins.h"
82 #include "utils/fmgroids.h"
83 #include "utils/lsyscache.h"
84 #include "utils/memutils.h"
85 #include "utils/regproc.h"
86 #include "utils/syscache.h"
87 #include "utils/tqual.h"
88 
89 /*
90  * ObjectProperty
91  *
92  * This array provides a common part of system object structure; to help
93  * consolidate routines to handle various kind of object classes.
94  */
95 typedef struct
96 {
97  Oid class_oid; /* oid of catalog */
98  Oid oid_index_oid; /* oid of index on system oid column */
99  int oid_catcache_id; /* id of catcache on system oid column */
100  int name_catcache_id; /* id of catcache on (name,namespace), or
101  * (name) if the object does not live in a
102  * namespace */
103  AttrNumber attnum_name; /* attnum of name field */
104  AttrNumber attnum_namespace; /* attnum of namespace field */
105  AttrNumber attnum_owner; /* attnum of owner field */
106  AttrNumber attnum_acl; /* attnum of acl field */
107  AclObjectKind acl_kind; /* ACL_KIND_* of this object type */
108  bool is_nsp_name_unique; /* can the nsp/name combination (or name
109  * alone, if there's no namespace) be
110  * considered a unique identifier for an
111  * object of this class? */
113 
115 {
116  {
118  AmOidIndexId,
119  AMOID,
120  AMNAME,
125  -1,
126  true
127  },
128  {
131  -1,
132  -1,
137  -1,
138  false
139  },
140  {
143  COLLOID,
144  -1, /* COLLNAMEENCNSP also takes encoding */
150  true
151  },
152  {
155  CONSTROID,
156  -1,
161  -1,
162  false
163  },
164  {
167  CONVOID,
168  CONNAMENSP,
174  true
175  },
176  {
179  DATABASEOID,
180  -1,
186  true
187  },
188  {
191  -1,
192  -1,
194  InvalidAttrNumber, /* extension doesn't belong to extnamespace */
198  true
199  },
200  {
209  ACL_KIND_FDW,
210  true
211  },
212  {
222  true
223  },
224  {
227  PROCOID,
228  -1, /* PROCNAMEARGSNSP also takes argument types */
234  false
235  },
236  {
239  LANGOID,
240  LANGNAME,
246  true
247  },
248  {
251  -1,
252  -1,
258  false
259  },
260  {
263  CLAOID,
264  -1, /* CLAAMNAMENSP also takes opcmethod */
270  true
271  },
272  {
275  OPEROID,
276  -1, /* OPERNAMENSP also takes left and right type */
282  false
283  },
284  {
287  OPFAMILYOID,
288  -1, /* OPFAMILYAMNAMENSP also takes opfmethod */
294  true
295  },
296  {
299  AUTHOID,
300  AUTHNAME,
305  -1,
306  true
307  },
308  {
311  -1,
312  -1,
317  -1,
318  false
319  },
320  {
323  NAMESPACEOID,
330  true
331  },
332  {
335  RELOID,
336  RELNAMENSP,
342  true
343  },
344  {
348  -1,
354  true
355  },
356  {
359  TRFOID,
361  },
362  {
365  -1,
366  -1,
371  -1,
372  false
373  },
374  {
377  -1,
378  -1,
383  -1,
384  false
385  },
386  {
396  true
397  },
398  {
401  TSCONFIGOID,
408  true
409  },
410  {
413  TSDICTOID,
420  true
421  },
422  {
425  TSPARSEROID,
431  -1,
432  true
433  },
434  {
443  -1,
444  true,
445  },
446  {
449  TYPEOID,
450  TYPENAMENSP,
456  true
457  },
458  {
468  true
469  },
470  {
480  true
481  },
482  {
485  STATEXTOID,
490  InvalidAttrNumber, /* no ACL (same as relation) */
492  true
493  }
494 };
495 
496 /*
497  * This struct maps the string object types as returned by
498  * getObjectTypeDescription into ObjType enum values. Note that some enum
499  * values can be obtained by different names, and that some string object types
500  * do not have corresponding values in the output enum. The user of this map
501  * must be careful to test for invalid values being returned.
502  *
503  * To ease maintenance, this follows the order of getObjectTypeDescription.
504  */
505 static const struct object_type_map
506 {
507  const char *tm_name;
509 }
510 
511  ObjectTypeMap[] =
512 {
513  /* OCLASS_CLASS, all kinds of relations */
514  {
515  "table", OBJECT_TABLE
516  },
517  {
518  "index", OBJECT_INDEX
519  },
520  {
521  "sequence", OBJECT_SEQUENCE
522  },
523  {
524  "toast table", -1
525  }, /* unmapped */
526  {
527  "view", OBJECT_VIEW
528  },
529  {
530  "materialized view", OBJECT_MATVIEW
531  },
532  {
533  "composite type", -1
534  }, /* unmapped */
535  {
536  "foreign table", OBJECT_FOREIGN_TABLE
537  },
538  {
539  "table column", OBJECT_COLUMN
540  },
541  {
542  "index column", -1
543  }, /* unmapped */
544  {
545  "sequence column", -1
546  }, /* unmapped */
547  {
548  "toast table column", -1
549  }, /* unmapped */
550  {
551  "view column", -1
552  }, /* unmapped */
553  {
554  "materialized view column", -1
555  }, /* unmapped */
556  {
557  "composite type column", -1
558  }, /* unmapped */
559  {
560  "foreign table column", OBJECT_COLUMN
561  },
562  /* OCLASS_PROC */
563  {
564  "aggregate", OBJECT_AGGREGATE
565  },
566  {
567  "function", OBJECT_FUNCTION
568  },
569  {
570  "procedure", OBJECT_PROCEDURE
571  },
572  /* OCLASS_TYPE */
573  {
574  "type", OBJECT_TYPE
575  },
576  /* OCLASS_CAST */
577  {
578  "cast", OBJECT_CAST
579  },
580  /* OCLASS_COLLATION */
581  {
582  "collation", OBJECT_COLLATION
583  },
584  /* OCLASS_CONSTRAINT */
585  {
586  "table constraint", OBJECT_TABCONSTRAINT
587  },
588  {
589  "domain constraint", OBJECT_DOMCONSTRAINT
590  },
591  /* OCLASS_CONVERSION */
592  {
593  "conversion", OBJECT_CONVERSION
594  },
595  /* OCLASS_DEFAULT */
596  {
597  "default value", OBJECT_DEFAULT
598  },
599  /* OCLASS_LANGUAGE */
600  {
601  "language", OBJECT_LANGUAGE
602  },
603  /* OCLASS_LARGEOBJECT */
604  {
605  "large object", OBJECT_LARGEOBJECT
606  },
607  /* OCLASS_OPERATOR */
608  {
609  "operator", OBJECT_OPERATOR
610  },
611  /* OCLASS_OPCLASS */
612  {
613  "operator class", OBJECT_OPCLASS
614  },
615  /* OCLASS_OPFAMILY */
616  {
617  "operator family", OBJECT_OPFAMILY
618  },
619  /* OCLASS_AM */
620  {
621  "access method", OBJECT_ACCESS_METHOD
622  },
623  /* OCLASS_AMOP */
624  {
625  "operator of access method", OBJECT_AMOP
626  },
627  /* OCLASS_AMPROC */
628  {
629  "function of access method", OBJECT_AMPROC
630  },
631  /* OCLASS_REWRITE */
632  {
633  "rule", OBJECT_RULE
634  },
635  /* OCLASS_TRIGGER */
636  {
637  "trigger", OBJECT_TRIGGER
638  },
639  /* OCLASS_SCHEMA */
640  {
641  "schema", OBJECT_SCHEMA
642  },
643  /* OCLASS_TSPARSER */
644  {
645  "text search parser", OBJECT_TSPARSER
646  },
647  /* OCLASS_TSDICT */
648  {
649  "text search dictionary", OBJECT_TSDICTIONARY
650  },
651  /* OCLASS_TSTEMPLATE */
652  {
653  "text search template", OBJECT_TSTEMPLATE
654  },
655  /* OCLASS_TSCONFIG */
656  {
657  "text search configuration", OBJECT_TSCONFIGURATION
658  },
659  /* OCLASS_ROLE */
660  {
661  "role", OBJECT_ROLE
662  },
663  /* OCLASS_DATABASE */
664  {
665  "database", OBJECT_DATABASE
666  },
667  /* OCLASS_TBLSPACE */
668  {
669  "tablespace", OBJECT_TABLESPACE
670  },
671  /* OCLASS_FDW */
672  {
673  "foreign-data wrapper", OBJECT_FDW
674  },
675  /* OCLASS_FOREIGN_SERVER */
676  {
677  "server", OBJECT_FOREIGN_SERVER
678  },
679  /* OCLASS_USER_MAPPING */
680  {
681  "user mapping", OBJECT_USER_MAPPING
682  },
683  /* OCLASS_DEFACL */
684  {
685  "default acl", OBJECT_DEFACL
686  },
687  /* OCLASS_EXTENSION */
688  {
689  "extension", OBJECT_EXTENSION
690  },
691  /* OCLASS_EVENT_TRIGGER */
692  {
693  "event trigger", OBJECT_EVENT_TRIGGER
694  },
695  /* OCLASS_POLICY */
696  {
697  "policy", OBJECT_POLICY
698  },
699  /* OCLASS_PUBLICATION */
700  {
701  "publication", OBJECT_PUBLICATION
702  },
703  /* OCLASS_PUBLICATION_REL */
704  {
705  "publication relation", OBJECT_PUBLICATION_REL
706  },
707  /* OCLASS_SUBSCRIPTION */
708  {
709  "subscription", OBJECT_SUBSCRIPTION
710  },
711  /* OCLASS_TRANSFORM */
712  {
713  "transform", OBJECT_TRANSFORM
714  },
715  /* OBJECT_STATISTIC_EXT */
716  {
717  "statistics object", OBJECT_STATISTIC_EXT
718  }
719 };
720 
722 {
723  InvalidOid,
724  InvalidOid,
725  0
726 };
727 
729  Value *strval, bool missing_ok);
731  List *object, Relation *relp,
732  LOCKMODE lockmode, bool missing_ok);
734  List *object, Relation *relp, bool missing_ok);
736  List *object, Relation *relp,
737  LOCKMODE lockmode, bool missing_ok);
739  List *object, Relation *relp, LOCKMODE lockmode,
740  bool missing_ok);
742  TypeName *typename, bool missing_ok);
743 static ObjectAddress get_object_address_opcf(ObjectType objtype, List *object,
744  bool missing_ok);
746  List *object, bool missing_ok);
747 
749  bool missing_ok);
751  Relation *relp,
752  bool missing_ok);
754  bool missing_ok);
755 static const ObjectPropertyType *get_object_property_data(Oid class_id);
756 
757 static void getRelationDescription(StringInfo buffer, Oid relid);
758 static void getOpFamilyDescription(StringInfo buffer, Oid opfid);
759 static void getRelationTypeDescription(StringInfo buffer, Oid relid,
760  int32 objectSubId);
761 static void getProcedureTypeDescription(StringInfo buffer, Oid procid);
762 static void getConstraintTypeDescription(StringInfo buffer, Oid constroid);
763 static void getOpFamilyIdentity(StringInfo buffer, Oid opfid, List **object);
764 static void getRelationIdentity(StringInfo buffer, Oid relid, List **object);
765 
766 /*
767  * Translate an object name and arguments (as passed by the parser) to an
768  * ObjectAddress.
769  *
770  * The returned object will be locked using the specified lockmode. If a
771  * sub-object is looked up, the parent object will be locked instead.
772  *
773  * If the object is a relation or a child object of a relation (e.g. an
774  * attribute or constraint), the relation is also opened and *relp receives
775  * the open relcache entry pointer; otherwise, *relp is set to NULL. This
776  * is a bit grotty but it makes life simpler, since the caller will
777  * typically need the relcache entry too. Caller must close the relcache
778  * entry when done with it. The relation is locked with the specified lockmode
779  * if the target object is the relation itself or an attribute, but for other
780  * child objects, only AccessShareLock is acquired on the relation.
781  *
782  * If the object is not found, an error is thrown, unless missing_ok is
783  * true. In this case, no lock is acquired, relp is set to NULL, and the
784  * returned address has objectId set to InvalidOid.
785  *
786  * We don't currently provide a function to release the locks acquired here;
787  * typically, the lock must be held until commit to guard against a concurrent
788  * drop operation.
789  *
790  * Note: If the object is not found, we don't give any indication of the
791  * reason. (It might have been a missing schema if the name was qualified, or
792  * a nonexistent type name in case of a cast, function or operator; etc).
793  * Currently there is only one caller that might be interested in such info, so
794  * we don't spend much effort here. If more callers start to care, it might be
795  * better to add some support for that in this function.
796  */
799  Relation *relp, LOCKMODE lockmode, bool missing_ok)
800 {
801  ObjectAddress address;
802  ObjectAddress old_address = {InvalidOid, InvalidOid, 0};
803  Relation relation = NULL;
804  uint64 inval_count;
805 
806  /* Some kind of lock must be taken. */
807  Assert(lockmode != NoLock);
808 
809  for (;;)
810  {
811  /*
812  * Remember this value, so that, after looking up the object name and
813  * locking it, we can check whether any invalidation messages have
814  * been processed that might require a do-over.
815  */
816  inval_count = SharedInvalidMessageCounter;
817 
818  /* Look up object address. */
819  switch (objtype)
820  {
821  case OBJECT_INDEX:
822  case OBJECT_SEQUENCE:
823  case OBJECT_TABLE:
824  case OBJECT_VIEW:
825  case OBJECT_MATVIEW:
827  address =
828  get_relation_by_qualified_name(objtype, castNode(List, object),
829  &relation, lockmode,
830  missing_ok);
831  break;
832  case OBJECT_COLUMN:
833  address =
834  get_object_address_attribute(objtype, castNode(List, object),
835  &relation, lockmode,
836  missing_ok);
837  break;
838  case OBJECT_DEFAULT:
839  address =
840  get_object_address_attrdef(objtype, castNode(List, object),
841  &relation, lockmode,
842  missing_ok);
843  break;
844  case OBJECT_RULE:
845  case OBJECT_TRIGGER:
847  case OBJECT_POLICY:
848  address = get_object_address_relobject(objtype, castNode(List, object),
849  &relation, missing_ok);
850  break;
852  {
853  List *objlist;
854  ObjectAddress domaddr;
855  char *constrname;
856 
857  objlist = castNode(List, object);
859  linitial_node(TypeName, objlist),
860  missing_ok);
861  constrname = strVal(lsecond(objlist));
862 
863  address.classId = ConstraintRelationId;
864  address.objectId = get_domain_constraint_oid(domaddr.objectId,
865  constrname, missing_ok);
866  address.objectSubId = 0;
867 
868  }
869  break;
870  case OBJECT_DATABASE:
871  case OBJECT_EXTENSION:
872  case OBJECT_TABLESPACE:
873  case OBJECT_ROLE:
874  case OBJECT_SCHEMA:
875  case OBJECT_LANGUAGE:
876  case OBJECT_FDW:
880  case OBJECT_PUBLICATION:
881  case OBJECT_SUBSCRIPTION:
882  address = get_object_address_unqualified(objtype,
883  (Value *) object, missing_ok);
884  break;
885  case OBJECT_TYPE:
886  case OBJECT_DOMAIN:
887  address = get_object_address_type(objtype, castNode(TypeName, object), missing_ok);
888  break;
889  case OBJECT_AGGREGATE:
890  case OBJECT_FUNCTION:
891  case OBJECT_PROCEDURE:
892  case OBJECT_ROUTINE:
893  address.classId = ProcedureRelationId;
894  address.objectId = LookupFuncWithArgs(objtype, 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 \"%c\", \"%c\", \"%c\", \"%c\", \"%c\".",
1859  }
1860 
1861  /*
1862  * Look up user ID. Behave as "default ACL not found" if the user doesn't
1863  * exist.
1864  */
1866  CStringGetDatum(username));
1867  if (!HeapTupleIsValid(tp))
1868  goto not_found;
1869  userid = HeapTupleGetOid(tp);
1870  ReleaseSysCache(tp);
1871 
1872  /*
1873  * If a schema name was given, look up its OID. If it doesn't exist,
1874  * behave as "default ACL not found".
1875  */
1876  if (schema)
1877  {
1878  schemaid = get_namespace_oid(schema, true);
1879  if (schemaid == InvalidOid)
1880  goto not_found;
1881  }
1882  else
1883  schemaid = InvalidOid;
1884 
1885  /* Finally, look up the pg_default_acl object */
1887  ObjectIdGetDatum(userid),
1888  ObjectIdGetDatum(schemaid),
1889  CharGetDatum(objtype));
1890  if (!HeapTupleIsValid(tp))
1891  goto not_found;
1892 
1893  address.objectId = HeapTupleGetOid(tp);
1894  ReleaseSysCache(tp);
1895 
1896  return address;
1897 
1898 not_found:
1899  if (!missing_ok)
1900  {
1901  if (schema)
1902  ereport(ERROR,
1903  (errcode(ERRCODE_UNDEFINED_OBJECT),
1904  errmsg("default ACL for user \"%s\" in schema \"%s\" on %s does not exist",
1905  username, schema, objtype_str)));
1906  else
1907  ereport(ERROR,
1908  (errcode(ERRCODE_UNDEFINED_OBJECT),
1909  errmsg("default ACL for user \"%s\" on %s does not exist",
1910  username, objtype_str)));
1911  }
1912  return address;
1913 }
1914 
1915 /*
1916  * Convert an array of TEXT into a List of string Values, as emitted by the
1917  * parser, which is what get_object_address uses as input.
1918  */
1919 static List *
1921 {
1922  Datum *elems;
1923  bool *nulls;
1924  int nelems;
1925  List *list = NIL;
1926  int i;
1927 
1928  deconstruct_array(arr, TEXTOID, -1, false, 'i',
1929  &elems, &nulls, &nelems);
1930 
1931  for (i = 0; i < nelems; i++)
1932  {
1933  if (nulls[i])
1934  ereport(ERROR,
1935  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1936  errmsg("name or argument lists may not contain nulls")));
1937  list = lappend(list, makeString(TextDatumGetCString(elems[i])));
1938  }
1939 
1940  return list;
1941 }
1942 
1943 /*
1944  * SQL-callable version of get_object_address
1945  */
1946 Datum
1948 {
1949  char *ttype = TextDatumGetCString(PG_GETARG_DATUM(0));
1950  ArrayType *namearr = PG_GETARG_ARRAYTYPE_P(1);
1951  ArrayType *argsarr = PG_GETARG_ARRAYTYPE_P(2);
1952  int itype;
1953  ObjectType type;
1954  List *name = NIL;
1955  TypeName *typename = NULL;
1956  List *args = NIL;
1957  Node *objnode = NULL;
1958  ObjectAddress addr;
1959  TupleDesc tupdesc;
1960  Datum values[3];
1961  bool nulls[3];
1962  HeapTuple htup;
1963  Relation relation;
1964 
1965  /* Decode object type, raise error if unknown */
1966  itype = read_objtype_from_string(ttype);
1967  if (itype < 0)
1968  ereport(ERROR,
1969  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1970  errmsg("unsupported object type \"%s\"", ttype)));
1971  type = (ObjectType) itype;
1972 
1973  /*
1974  * Convert the text array to the representation appropriate for the given
1975  * object type. Most use a simple string Values list, but there are some
1976  * exceptions.
1977  */
1978  if (type == OBJECT_TYPE || type == OBJECT_DOMAIN || type == OBJECT_CAST ||
1979  type == OBJECT_TRANSFORM || type == OBJECT_DOMCONSTRAINT)
1980  {
1981  Datum *elems;
1982  bool *nulls;
1983  int nelems;
1984 
1985  deconstruct_array(namearr, TEXTOID, -1, false, 'i',
1986  &elems, &nulls, &nelems);
1987  if (nelems != 1)
1988  ereport(ERROR,
1989  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1990  errmsg("name list length must be exactly %d", 1)));
1991  if (nulls[0])
1992  ereport(ERROR,
1993  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1994  errmsg("name or argument lists may not contain nulls")));
1995  typename = typeStringToTypeName(TextDatumGetCString(elems[0]));
1996  }
1997  else if (type == OBJECT_LARGEOBJECT)
1998  {
1999  Datum *elems;
2000  bool *nulls;
2001  int nelems;
2002 
2003  deconstruct_array(namearr, TEXTOID, -1, false, 'i',
2004  &elems, &nulls, &nelems);
2005  if (nelems != 1)
2006  ereport(ERROR,
2007  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2008  errmsg("name list length must be exactly %d", 1)));
2009  if (nulls[0])
2010  ereport(ERROR,
2011  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2012  errmsg("large object OID may not be null")));
2013  objnode = (Node *) makeFloat(TextDatumGetCString(elems[0]));
2014  }
2015  else
2016  {
2017  name = textarray_to_strvaluelist(namearr);
2018  if (list_length(name) < 1)
2019  ereport(ERROR,
2020  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2021  errmsg("name list length must be at least %d", 1)));
2022  }
2023 
2024  /*
2025  * If args are given, decode them according to the object type.
2026  */
2027  if (type == OBJECT_AGGREGATE ||
2028  type == OBJECT_FUNCTION ||
2029  type == OBJECT_PROCEDURE ||
2030  type == OBJECT_ROUTINE ||
2031  type == OBJECT_OPERATOR ||
2032  type == OBJECT_CAST ||
2033  type == OBJECT_AMOP ||
2034  type == OBJECT_AMPROC)
2035  {
2036  /* in these cases, the args list must be of TypeName */
2037  Datum *elems;
2038  bool *nulls;
2039  int nelems;
2040  int i;
2041 
2042  deconstruct_array(argsarr, TEXTOID, -1, false, 'i',
2043  &elems, &nulls, &nelems);
2044 
2045  args = NIL;
2046  for (i = 0; i < nelems; i++)
2047  {
2048  if (nulls[i])
2049  ereport(ERROR,
2050  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2051  errmsg("name or argument lists may not contain nulls")));
2052  args = lappend(args,
2054  }
2055  }
2056  else
2057  {
2058  /* For all other object types, use string Values */
2059  args = textarray_to_strvaluelist(argsarr);
2060  }
2061 
2062  /*
2063  * get_object_address is pretty sensitive to the length its input lists;
2064  * check that they're what it wants.
2065  */
2066  switch (type)
2067  {
2068  case OBJECT_DOMCONSTRAINT:
2069  case OBJECT_CAST:
2070  case OBJECT_USER_MAPPING:
2072  case OBJECT_DEFACL:
2073  case OBJECT_TRANSFORM:
2074  if (list_length(args) != 1)
2075  ereport(ERROR,
2076  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2077  errmsg("argument list length must be exactly %d", 1)));
2078  break;
2079  case OBJECT_OPFAMILY:
2080  case OBJECT_OPCLASS:
2081  if (list_length(name) < 2)
2082  ereport(ERROR,
2083  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2084  errmsg("name list length must be at least %d", 2)));
2085  break;
2086  case OBJECT_AMOP:
2087  case OBJECT_AMPROC:
2088  if (list_length(name) < 3)
2089  ereport(ERROR,
2090  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2091  errmsg("name list length must be at least %d", 3)));
2092  /* fall through to check args length */
2093  case OBJECT_OPERATOR:
2094  if (list_length(args) != 2)
2095  ereport(ERROR,
2096  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2097  errmsg("argument list length must be exactly %d", 2)));
2098  break;
2099  default:
2100  break;
2101  }
2102 
2103  /*
2104  * Now build the Node type that get_object_address() expects for the given
2105  * type.
2106  */
2107  switch (type)
2108  {
2109  case OBJECT_TABLE:
2110  case OBJECT_SEQUENCE:
2111  case OBJECT_VIEW:
2112  case OBJECT_MATVIEW:
2113  case OBJECT_INDEX:
2114  case OBJECT_FOREIGN_TABLE:
2115  case OBJECT_COLUMN:
2116  case OBJECT_ATTRIBUTE:
2117  case OBJECT_COLLATION:
2118  case OBJECT_CONVERSION:
2119  case OBJECT_STATISTIC_EXT:
2120  case OBJECT_TSPARSER:
2121  case OBJECT_TSDICTIONARY:
2122  case OBJECT_TSTEMPLATE:
2124  case OBJECT_DEFAULT:
2125  case OBJECT_POLICY:
2126  case OBJECT_RULE:
2127  case OBJECT_TRIGGER:
2128  case OBJECT_TABCONSTRAINT:
2129  case OBJECT_OPCLASS:
2130  case OBJECT_OPFAMILY:
2131  objnode = (Node *) name;
2132  break;
2133  case OBJECT_ACCESS_METHOD:
2134  case OBJECT_DATABASE:
2135  case OBJECT_EVENT_TRIGGER:
2136  case OBJECT_EXTENSION:
2137  case OBJECT_FDW:
2138  case OBJECT_FOREIGN_SERVER:
2139  case OBJECT_LANGUAGE:
2140  case OBJECT_PUBLICATION:
2141  case OBJECT_ROLE:
2142  case OBJECT_SCHEMA:
2143  case OBJECT_SUBSCRIPTION:
2144  case OBJECT_TABLESPACE:
2145  if (list_length(name) != 1)
2146  ereport(ERROR,
2147  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2148  errmsg("name list length must be exactly %d", 1)));
2149  objnode = linitial(name);
2150  break;
2151  case OBJECT_TYPE:
2152  case OBJECT_DOMAIN:
2153  objnode = (Node *) typename;
2154  break;
2155  case OBJECT_CAST:
2156  case OBJECT_DOMCONSTRAINT:
2157  case OBJECT_TRANSFORM:
2158  objnode = (Node *) list_make2(typename, linitial(args));
2159  break;
2161  objnode = (Node *) list_make2(name, linitial(args));
2162  break;
2163  case OBJECT_USER_MAPPING:
2164  objnode = (Node *) list_make2(linitial(name), linitial(args));
2165  break;
2166  case OBJECT_DEFACL:
2167  objnode = (Node *) lcons(linitial(args), name);
2168  break;
2169  case OBJECT_AMOP:
2170  case OBJECT_AMPROC:
2171  objnode = (Node *) list_make2(name, args);
2172  break;
2173  case OBJECT_FUNCTION:
2174  case OBJECT_PROCEDURE:
2175  case OBJECT_ROUTINE:
2176  case OBJECT_AGGREGATE:
2177  case OBJECT_OPERATOR:
2178  {
2180 
2181  owa->objname = name;
2182  owa->objargs = args;
2183  objnode = (Node *) owa;
2184  break;
2185  }
2186  case OBJECT_LARGEOBJECT:
2187  /* already handled above */
2188  break;
2189  /* no default, to let compiler warn about missing case */
2190  }
2191 
2192  if (objnode == NULL)
2193  elog(ERROR, "unrecognized object type: %d", type);
2194 
2195  addr = get_object_address(type, objnode,
2196  &relation, AccessShareLock, false);
2197 
2198  /* We don't need the relcache entry, thank you very much */
2199  if (relation)
2200  relation_close(relation, AccessShareLock);
2201 
2202  tupdesc = CreateTemplateTupleDesc(3, false);
2203  TupleDescInitEntry(tupdesc, (AttrNumber) 1, "classid",
2204  OIDOID, -1, 0);
2205  TupleDescInitEntry(tupdesc, (AttrNumber) 2, "objid",
2206  OIDOID, -1, 0);
2207  TupleDescInitEntry(tupdesc, (AttrNumber) 3, "objsubid",
2208  INT4OID, -1, 0);
2209  tupdesc = BlessTupleDesc(tupdesc);
2210 
2211  values[0] = ObjectIdGetDatum(addr.classId);
2212  values[1] = ObjectIdGetDatum(addr.objectId);
2213  values[2] = Int32GetDatum(addr.objectSubId);
2214  nulls[0] = false;
2215  nulls[1] = false;
2216  nulls[2] = false;
2217 
2218  htup = heap_form_tuple(tupdesc, values, nulls);
2219 
2221 }
2222 
2223 /*
2224  * Check ownership of an object previously identified by get_object_address.
2225  */
2226 void
2228  Node *object, Relation relation)
2229 {
2230  switch (objtype)
2231  {
2232  case OBJECT_INDEX:
2233  case OBJECT_SEQUENCE:
2234  case OBJECT_TABLE:
2235  case OBJECT_VIEW:
2236  case OBJECT_MATVIEW:
2237  case OBJECT_FOREIGN_TABLE:
2238  case OBJECT_COLUMN:
2239  case OBJECT_RULE:
2240  case OBJECT_TRIGGER:
2241  case OBJECT_POLICY:
2242  case OBJECT_TABCONSTRAINT:
2243  if (!pg_class_ownercheck(RelationGetRelid(relation), roleid))
2245  RelationGetRelationName(relation));
2246  break;
2247  case OBJECT_DATABASE:
2248  if (!pg_database_ownercheck(address.objectId, roleid))
2250  strVal((Value *) object));
2251  break;
2252  case OBJECT_TYPE:
2253  case OBJECT_DOMAIN:
2254  case OBJECT_ATTRIBUTE:
2255  case OBJECT_DOMCONSTRAINT:
2256  if (!pg_type_ownercheck(address.objectId, roleid))
2258  break;
2259  case OBJECT_AGGREGATE:
2260  case OBJECT_FUNCTION:
2261  case OBJECT_PROCEDURE:
2262  case OBJECT_ROUTINE:
2263  if (!pg_proc_ownercheck(address.objectId, roleid))
2265  NameListToString((castNode(ObjectWithArgs, object))->objname));
2266  break;
2267  case OBJECT_OPERATOR:
2268  if (!pg_oper_ownercheck(address.objectId, roleid))
2270  NameListToString((castNode(ObjectWithArgs, object))->objname));
2271  break;
2272  case OBJECT_SCHEMA:
2273  if (!pg_namespace_ownercheck(address.objectId, roleid))
2275  strVal((Value *) object));
2276  break;
2277  case OBJECT_COLLATION:
2278  if (!pg_collation_ownercheck(address.objectId, roleid))
2280  NameListToString(castNode(List, object)));
2281  break;
2282  case OBJECT_CONVERSION:
2283  if (!pg_conversion_ownercheck(address.objectId, roleid))
2285  NameListToString(castNode(List, object)));
2286  break;
2287  case OBJECT_EXTENSION:
2288  if (!pg_extension_ownercheck(address.objectId, roleid))
2290  strVal((Value *) object));
2291  break;
2292  case OBJECT_FDW:
2293  if (!pg_foreign_data_wrapper_ownercheck(address.objectId, roleid))
2295  strVal((Value *) object));
2296  break;
2297  case OBJECT_FOREIGN_SERVER:
2298  if (!pg_foreign_server_ownercheck(address.objectId, roleid))
2300  strVal((Value *) object));
2301  break;
2302  case OBJECT_EVENT_TRIGGER:
2303  if (!pg_event_trigger_ownercheck(address.objectId, roleid))
2305  strVal((Value *) object));
2306  break;
2307  case OBJECT_LANGUAGE:
2308  if (!pg_language_ownercheck(address.objectId, roleid))
2310  strVal((Value *) object));
2311  break;
2312  case OBJECT_OPCLASS:
2313  if (!pg_opclass_ownercheck(address.objectId, roleid))
2315  NameListToString(castNode(List, object)));
2316  break;
2317  case OBJECT_OPFAMILY:
2318  if (!pg_opfamily_ownercheck(address.objectId, roleid))
2320  NameListToString(castNode(List, object)));
2321  break;
2322  case OBJECT_LARGEOBJECT:
2323  if (!lo_compat_privileges &&
2324  !pg_largeobject_ownercheck(address.objectId, roleid))
2325  ereport(ERROR,
2326  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2327  errmsg("must be owner of large object %u",
2328  address.objectId)));
2329  break;
2330  case OBJECT_CAST:
2331  {
2332  /* We can only check permissions on the source/target types */
2333  TypeName *sourcetype = linitial_node(TypeName, castNode(List, object));
2334  TypeName *targettype = lsecond_node(TypeName, castNode(List, object));
2335  Oid sourcetypeid = typenameTypeId(NULL, sourcetype);
2336  Oid targettypeid = typenameTypeId(NULL, targettype);
2337 
2338  if (!pg_type_ownercheck(sourcetypeid, roleid)
2339  && !pg_type_ownercheck(targettypeid, roleid))
2340  ereport(ERROR,
2341  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2342  errmsg("must be owner of type %s or type %s",
2343  format_type_be(sourcetypeid),
2344  format_type_be(targettypeid))));
2345  }
2346  break;
2347  case OBJECT_PUBLICATION:
2348  if (!pg_publication_ownercheck(address.objectId, roleid))
2350  strVal((Value *) object));
2351  break;
2352  case OBJECT_SUBSCRIPTION:
2353  if (!pg_subscription_ownercheck(address.objectId, roleid))
2355  strVal((Value *) object));
2356  break;
2357  case OBJECT_TRANSFORM:
2358  {
2359  TypeName *typename = linitial_node(TypeName, castNode(List, object));
2360  Oid typeid = typenameTypeId(NULL, typename);
2361 
2362  if (!pg_type_ownercheck(typeid, roleid))
2364  }
2365  break;
2366  case OBJECT_TABLESPACE:
2367  if (!pg_tablespace_ownercheck(address.objectId, roleid))
2369  strVal((Value *) object));
2370  break;
2371  case OBJECT_TSDICTIONARY:
2372  if (!pg_ts_dict_ownercheck(address.objectId, roleid))
2374  NameListToString(castNode(List, object)));
2375  break;
2377  if (!pg_ts_config_ownercheck(address.objectId, roleid))
2379  NameListToString(castNode(List, object)));
2380  break;
2381  case OBJECT_ROLE:
2382 
2383  /*
2384  * We treat roles as being "owned" by those with CREATEROLE priv,
2385  * except that superusers are only owned by superusers.
2386  */
2387  if (superuser_arg(address.objectId))
2388  {
2389  if (!superuser_arg(roleid))
2390  ereport(ERROR,
2391  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2392  errmsg("must be superuser")));
2393  }
2394  else
2395  {
2396  if (!has_createrole_privilege(roleid))
2397  ereport(ERROR,
2398  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2399  errmsg("must have CREATEROLE privilege")));
2400  }
2401  break;
2402  case OBJECT_TSPARSER:
2403  case OBJECT_TSTEMPLATE:
2404  case OBJECT_ACCESS_METHOD:
2405  /* We treat these object types as being owned by superusers */
2406  if (!superuser_arg(roleid))
2407  ereport(ERROR,
2408  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2409  errmsg("must be superuser")));
2410  break;
2411  case OBJECT_STATISTIC_EXT:
2412  if (!pg_statistics_object_ownercheck(address.objectId, roleid))
2414  break;
2415  default:
2416  elog(ERROR, "unrecognized object type: %d",
2417  (int) objtype);
2418  }
2419 }
2420 
2421 /*
2422  * get_object_namespace
2423  *
2424  * Find the schema containing the specified object. For non-schema objects,
2425  * this function returns InvalidOid.
2426  */
2427 Oid
2429 {
2430  int cache;
2431  HeapTuple tuple;
2432  bool isnull;
2433  Oid oid;
2434  const ObjectPropertyType *property;
2435 
2436  /* If not owned by a namespace, just return InvalidOid. */
2437  property = get_object_property_data(address->classId);
2438  if (property->attnum_namespace == InvalidAttrNumber)
2439  return InvalidOid;
2440 
2441  /* Currently, we can only handle object types with system caches. */
2442  cache = property->oid_catcache_id;
2443  Assert(cache != -1);
2444 
2445  /* Fetch tuple from syscache and extract namespace attribute. */
2446  tuple = SearchSysCache1(cache, ObjectIdGetDatum(address->objectId));
2447  if (!HeapTupleIsValid(tuple))
2448  elog(ERROR, "cache lookup failed for cache %d oid %u",
2449  cache, address->objectId);
2450  oid = DatumGetObjectId(SysCacheGetAttr(cache,
2451  tuple,
2452  property->attnum_namespace,
2453  &isnull));
2454  Assert(!isnull);
2455  ReleaseSysCache(tuple);
2456 
2457  return oid;
2458 }
2459 
2460 /*
2461  * Return ObjectType for the given object type as given by
2462  * getObjectTypeDescription; if no valid ObjectType code exists, but it's a
2463  * possible output type from getObjectTypeDescription, return -1.
2464  * Otherwise, an error is thrown.
2465  */
2466 int
2467 read_objtype_from_string(const char *objtype)
2468 {
2469  int i;
2470 
2471  for (i = 0; i < lengthof(ObjectTypeMap); i++)
2472  {
2473  if (strcmp(ObjectTypeMap[i].tm_name, objtype) == 0)
2474  return ObjectTypeMap[i].tm_type;
2475  }
2476  ereport(ERROR,
2477  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2478  errmsg("unrecognized object type \"%s\"", objtype)));
2479 
2480  return -1; /* keep compiler quiet */
2481 }
2482 
2483 /*
2484  * Interfaces to reference fields of ObjectPropertyType
2485  */
2486 Oid
2488 {
2489  const ObjectPropertyType *prop = get_object_property_data(class_id);
2490 
2491  return prop->oid_index_oid;
2492 }
2493 
2494 int
2496 {
2497  const ObjectPropertyType *prop = get_object_property_data(class_id);
2498 
2499  return prop->oid_catcache_id;
2500 }
2501 
2502 int
2504 {
2505  const ObjectPropertyType *prop = get_object_property_data(class_id);
2506 
2507  return prop->name_catcache_id;
2508 }
2509 
2510 AttrNumber
2512 {
2513  const ObjectPropertyType *prop = get_object_property_data(class_id);
2514 
2515  return prop->attnum_name;
2516 }
2517 
2518 AttrNumber
2520 {
2521  const ObjectPropertyType *prop = get_object_property_data(class_id);
2522 
2523  return prop->attnum_namespace;
2524 }
2525 
2526 AttrNumber
2528 {
2529  const ObjectPropertyType *prop = get_object_property_data(class_id);
2530 
2531  return prop->attnum_owner;
2532 }
2533 
2534 AttrNumber
2536 {
2537  const ObjectPropertyType *prop = get_object_property_data(class_id);
2538 
2539  return prop->attnum_acl;
2540 }
2541 
2544 {
2545  const ObjectPropertyType *prop = get_object_property_data(class_id);
2546 
2547  return prop->acl_kind;
2548 }
2549 
2550 bool
2552 {
2553  const ObjectPropertyType *prop = get_object_property_data(class_id);
2554 
2555  return prop->is_nsp_name_unique;
2556 }
2557 
2558 /*
2559  * Return whether we have useful data for the given object class in the
2560  * ObjectProperty table.
2561  */
2562 bool
2564 {
2565  int index;
2566 
2567  for (index = 0; index < lengthof(ObjectProperty); index++)
2568  {
2569  if (ObjectProperty[index].class_oid == class_id)
2570  return true;
2571  }
2572 
2573  return false;
2574 }
2575 
2576 /*
2577  * Find ObjectProperty structure by class_id.
2578  */
2579 static const ObjectPropertyType *
2581 {
2582  static const ObjectPropertyType *prop_last = NULL;
2583  int index;
2584 
2585  /*
2586  * A shortcut to speed up multiple consecutive lookups of a particular
2587  * object class.
2588  */
2589  if (prop_last && prop_last->class_oid == class_id)
2590  return prop_last;
2591 
2592  for (index = 0; index < lengthof(ObjectProperty); index++)
2593  {
2594  if (ObjectProperty[index].class_oid == class_id)
2595  {
2596  prop_last = &ObjectProperty[index];
2597  return &ObjectProperty[index];
2598  }
2599  }
2600 
2601  ereport(ERROR,
2602  (errmsg_internal("unrecognized class ID: %u", class_id)));
2603 
2604  return NULL; /* keep MSC compiler happy */
2605 }
2606 
2607 /*
2608  * Return a copy of the tuple for the object with the given object OID, from
2609  * the given catalog (which must have been opened by the caller and suitably
2610  * locked). NULL is returned if the OID is not found.
2611  *
2612  * We try a syscache first, if available.
2613  */
2614 HeapTuple
2616 {
2617  HeapTuple tuple;
2618  Oid classId = RelationGetRelid(catalog);
2619  int oidCacheId = get_object_catcache_oid(classId);
2620 
2621  if (oidCacheId > 0)
2622  {
2623  tuple = SearchSysCacheCopy1(oidCacheId, ObjectIdGetDatum(objectId));
2624  if (!HeapTupleIsValid(tuple)) /* should not happen */
2625  return NULL;
2626  }
2627  else
2628  {
2629  Oid oidIndexId = get_object_oid_index(classId);
2630  SysScanDesc scan;
2631  ScanKeyData skey;
2632 
2633  Assert(OidIsValid(oidIndexId));
2634 
2635  ScanKeyInit(&skey,
2637  BTEqualStrategyNumber, F_OIDEQ,
2638  ObjectIdGetDatum(objectId));
2639 
2640  scan = systable_beginscan(catalog, oidIndexId, true,
2641  NULL, 1, &skey);
2642  tuple = systable_getnext(scan);
2643  if (!HeapTupleIsValid(tuple))
2644  {
2645  systable_endscan(scan);
2646  return NULL;
2647  }
2648  tuple = heap_copytuple(tuple);
2649 
2650  systable_endscan(scan);
2651  }
2652 
2653  return tuple;
2654 }
2655 
2656 /*
2657  * getObjectDescription: build an object description for messages
2658  *
2659  * The result is a palloc'd string.
2660  */
2661 char *
2663 {
2665 
2666  initStringInfo(&buffer);
2667 
2668  switch (getObjectClass(object))
2669  {
2670  case OCLASS_CLASS:
2671  getRelationDescription(&buffer, object->objectId);
2672  if (object->objectSubId != 0)
2673  appendStringInfo(&buffer, _(" column %s"),
2675  object->objectSubId));
2676  break;
2677 
2678  case OCLASS_PROC:
2679  appendStringInfo(&buffer, _("function %s"),
2680  format_procedure(object->objectId));
2681  break;
2682 
2683  case OCLASS_TYPE:
2684  appendStringInfo(&buffer, _("type %s"),
2685  format_type_be(object->objectId));
2686  break;
2687 
2688  case OCLASS_CAST:
2689  {
2690  Relation castDesc;
2691  ScanKeyData skey[1];
2692  SysScanDesc rcscan;
2693  HeapTuple tup;
2694  Form_pg_cast castForm;
2695 
2697 
2698  ScanKeyInit(&skey[0],
2700  BTEqualStrategyNumber, F_OIDEQ,
2701  ObjectIdGetDatum(object->objectId));
2702 
2703  rcscan = systable_beginscan(castDesc, CastOidIndexId, true,
2704  NULL, 1, skey);
2705 
2706  tup = systable_getnext(rcscan);
2707 
2708  if (!HeapTupleIsValid(tup))
2709  elog(ERROR, "could not find tuple for cast %u",
2710  object->objectId);
2711 
2712  castForm = (Form_pg_cast) GETSTRUCT(tup);
2713 
2714  appendStringInfo(&buffer, _("cast from %s to %s"),
2715  format_type_be(castForm->castsource),
2716  format_type_be(castForm->casttarget));
2717 
2718  systable_endscan(rcscan);
2719  heap_close(castDesc, AccessShareLock);
2720  break;
2721  }
2722 
2723  case OCLASS_COLLATION:
2724  {
2725  HeapTuple collTup;
2726  Form_pg_collation coll;
2727 
2728  collTup = SearchSysCache1(COLLOID,
2729  ObjectIdGetDatum(object->objectId));
2730  if (!HeapTupleIsValid(collTup))
2731  elog(ERROR, "cache lookup failed for collation %u",
2732  object->objectId);
2733  coll = (Form_pg_collation) GETSTRUCT(collTup);
2734  appendStringInfo(&buffer, _("collation %s"),
2735  NameStr(coll->collname));
2736  ReleaseSysCache(collTup);
2737  break;
2738  }
2739 
2740  case OCLASS_CONSTRAINT:
2741  {
2742  HeapTuple conTup;
2743  Form_pg_constraint con;
2744 
2745  conTup = SearchSysCache1(CONSTROID,
2746  ObjectIdGetDatum(object->objectId));
2747  if (!HeapTupleIsValid(conTup))
2748  elog(ERROR, "cache lookup failed for constraint %u",
2749  object->objectId);
2750  con = (Form_pg_constraint) GETSTRUCT(conTup);
2751 
2752  if (OidIsValid(con->conrelid))
2753  {
2754  StringInfoData rel;
2755 
2756  initStringInfo(&rel);
2757  getRelationDescription(&rel, con->conrelid);
2758  appendStringInfo(&buffer, _("constraint %s on %s"),
2759  NameStr(con->conname), rel.data);
2760  pfree(rel.data);
2761  }
2762  else
2763  {
2764  appendStringInfo(&buffer, _("constraint %s"),
2765  NameStr(con->conname));
2766  }
2767 
2768  ReleaseSysCache(conTup);
2769  break;
2770  }
2771 
2772  case OCLASS_CONVERSION:
2773  {
2774  HeapTuple conTup;
2775 
2776  conTup = SearchSysCache1(CONVOID,
2777  ObjectIdGetDatum(object->objectId));
2778  if (!HeapTupleIsValid(conTup))
2779  elog(ERROR, "cache lookup failed for conversion %u",
2780  object->objectId);
2781  appendStringInfo(&buffer, _("conversion %s"),
2782  NameStr(((Form_pg_conversion) GETSTRUCT(conTup))->conname));
2783  ReleaseSysCache(conTup);
2784  break;
2785  }
2786 
2787  case OCLASS_DEFAULT:
2788  {
2789  Relation attrdefDesc;
2790  ScanKeyData skey[1];
2791  SysScanDesc adscan;
2792  HeapTuple tup;
2793  Form_pg_attrdef attrdef;
2794  ObjectAddress colobject;
2795 
2797 
2798  ScanKeyInit(&skey[0],
2800  BTEqualStrategyNumber, F_OIDEQ,
2801  ObjectIdGetDatum(object->objectId));
2802 
2803  adscan = systable_beginscan(attrdefDesc, AttrDefaultOidIndexId,
2804  true, NULL, 1, skey);
2805 
2806  tup = systable_getnext(adscan);
2807 
2808  if (!HeapTupleIsValid(tup))
2809  elog(ERROR, "could not find tuple for attrdef %u",
2810  object->objectId);
2811 
2812  attrdef = (Form_pg_attrdef) GETSTRUCT(tup);
2813 
2814  colobject.classId = RelationRelationId;
2815  colobject.objectId = attrdef->adrelid;
2816  colobject.objectSubId = attrdef->adnum;
2817 
2818  appendStringInfo(&buffer, _("default for %s"),
2819  getObjectDescription(&colobject));
2820 
2821  systable_endscan(adscan);
2822  heap_close(attrdefDesc, AccessShareLock);
2823  break;
2824  }
2825 
2826  case OCLASS_LANGUAGE:
2827  appendStringInfo(&buffer, _("language %s"),
2828  get_language_name(object->objectId, false));
2829  break;
2830 
2831  case OCLASS_LARGEOBJECT:
2832  appendStringInfo(&buffer, _("large object %u"),
2833  object->objectId);
2834  break;
2835 
2836  case OCLASS_OPERATOR:
2837  appendStringInfo(&buffer, _("operator %s"),
2838  format_operator(object->objectId));
2839  break;
2840 
2841  case OCLASS_OPCLASS:
2842  {
2843  HeapTuple opcTup;
2844  Form_pg_opclass opcForm;
2845  HeapTuple amTup;
2846  Form_pg_am amForm;
2847  char *nspname;
2848 
2849  opcTup = SearchSysCache1(CLAOID,
2850  ObjectIdGetDatum(object->objectId));
2851  if (!HeapTupleIsValid(opcTup))
2852  elog(ERROR, "cache lookup failed for opclass %u",
2853  object->objectId);
2854  opcForm = (Form_pg_opclass) GETSTRUCT(opcTup);
2855 
2856  amTup = SearchSysCache1(AMOID,
2857  ObjectIdGetDatum(opcForm->opcmethod));
2858  if (!HeapTupleIsValid(amTup))
2859  elog(ERROR, "cache lookup failed for access method %u",
2860  opcForm->opcmethod);
2861  amForm = (Form_pg_am) GETSTRUCT(amTup);
2862 
2863  /* Qualify the name if not visible in search path */
2864  if (OpclassIsVisible(object->objectId))
2865  nspname = NULL;
2866  else
2867  nspname = get_namespace_name(opcForm->opcnamespace);
2868 
2869  appendStringInfo(&buffer, _("operator class %s for access method %s"),
2871  NameStr(opcForm->opcname)),
2872  NameStr(amForm->amname));
2873 
2874  ReleaseSysCache(amTup);
2875  ReleaseSysCache(opcTup);
2876  break;
2877  }
2878 
2879  case OCLASS_OPFAMILY:
2880  getOpFamilyDescription(&buffer, object->objectId);
2881  break;
2882 
2883  case OCLASS_AM:
2884  {
2885  HeapTuple tup;
2886 
2887  tup = SearchSysCache1(AMOID,
2888  ObjectIdGetDatum(object->objectId));
2889  if (!HeapTupleIsValid(tup))
2890  elog(ERROR, "cache lookup failed for access method %u",
2891  object->objectId);
2892  appendStringInfo(&buffer, _("access method %s"),
2893  NameStr(((Form_pg_am) GETSTRUCT(tup))->amname));
2894  ReleaseSysCache(tup);
2895  break;
2896  }
2897 
2898  case OCLASS_AMOP:
2899  {
2900  Relation amopDesc;
2901  HeapTuple tup;
2902  ScanKeyData skey[1];
2903  SysScanDesc amscan;
2904  Form_pg_amop amopForm;
2905  StringInfoData opfam;
2906 
2908  AccessShareLock);
2909 
2910  ScanKeyInit(&skey[0],
2912  BTEqualStrategyNumber, F_OIDEQ,
2913  ObjectIdGetDatum(object->objectId));
2914 
2915  amscan = systable_beginscan(amopDesc, AccessMethodOperatorOidIndexId, true,
2916  NULL, 1, skey);
2917 
2918  tup = systable_getnext(amscan);
2919 
2920  if (!HeapTupleIsValid(tup))
2921  elog(ERROR, "could not find tuple for amop entry %u",
2922  object->objectId);
2923 
2924  amopForm = (Form_pg_amop) GETSTRUCT(tup);
2925 
2926  initStringInfo(&opfam);
2927  getOpFamilyDescription(&opfam, amopForm->amopfamily);
2928 
2929  /*------
2930  translator: %d is the operator strategy (a number), the
2931  first two %s's are data type names, the third %s is the
2932  description of the operator family, and the last %s is the
2933  textual form of the operator with arguments. */
2934  appendStringInfo(&buffer, _("operator %d (%s, %s) of %s: %s"),
2935  amopForm->amopstrategy,
2936  format_type_be(amopForm->amoplefttype),
2937  format_type_be(amopForm->amoprighttype),
2938  opfam.data,
2939  format_operator(amopForm->amopopr));
2940 
2941  pfree(opfam.data);
2942 
2943  systable_endscan(amscan);
2944  heap_close(amopDesc, AccessShareLock);
2945  break;
2946  }
2947 
2948  case OCLASS_AMPROC:
2949  {
2950  Relation amprocDesc;
2951  ScanKeyData skey[1];
2952  SysScanDesc amscan;
2953  HeapTuple tup;
2954  Form_pg_amproc amprocForm;
2955  StringInfoData opfam;
2956 
2958  AccessShareLock);
2959 
2960  ScanKeyInit(&skey[0],
2962  BTEqualStrategyNumber, F_OIDEQ,
2963  ObjectIdGetDatum(object->objectId));
2964 
2965  amscan = systable_beginscan(amprocDesc, AccessMethodProcedureOidIndexId, true,
2966  NULL, 1, skey);
2967 
2968  tup = systable_getnext(amscan);
2969 
2970  if (!HeapTupleIsValid(tup))
2971  elog(ERROR, "could not find tuple for amproc entry %u",
2972  object->objectId);
2973 
2974  amprocForm = (Form_pg_amproc) GETSTRUCT(tup);
2975 
2976  initStringInfo(&opfam);
2977  getOpFamilyDescription(&opfam, amprocForm->amprocfamily);
2978 
2979  /*------
2980  translator: %d is the function number, the first two %s's
2981  are data type names, the third %s is the description of the
2982  operator family, and the last %s is the textual form of the
2983  function with arguments. */
2984  appendStringInfo(&buffer, _("function %d (%s, %s) of %s: %s"),
2985  amprocForm->amprocnum,
2986  format_type_be(amprocForm->amproclefttype),
2987  format_type_be(amprocForm->amprocrighttype),
2988  opfam.data,
2989  format_procedure(amprocForm->amproc));
2990 
2991  pfree(opfam.data);
2992 
2993  systable_endscan(amscan);
2994  heap_close(amprocDesc, AccessShareLock);
2995  break;
2996  }
2997 
2998  case OCLASS_REWRITE:
2999  {
3000  Relation ruleDesc;
3001  ScanKeyData skey[1];
3002  SysScanDesc rcscan;
3003  HeapTuple tup;
3005 
3007 
3008  ScanKeyInit(&skey[0],
3010  BTEqualStrategyNumber, F_OIDEQ,
3011  ObjectIdGetDatum(object->objectId));
3012 
3013  rcscan = systable_beginscan(ruleDesc, RewriteOidIndexId, true,
3014  NULL, 1, skey);
3015 
3016  tup = systable_getnext(rcscan);
3017 
3018  if (!HeapTupleIsValid(tup))
3019  elog(ERROR, "could not find tuple for rule %u",
3020  object->objectId);
3021 
3022  rule = (Form_pg_rewrite) GETSTRUCT(tup);
3023 
3024  appendStringInfo(&buffer, _("rule %s on "),
3025  NameStr(rule->rulename));
3026  getRelationDescription(&buffer, rule->ev_class);
3027 
3028  systable_endscan(rcscan);
3029  heap_close(ruleDesc, AccessShareLock);
3030  break;
3031  }
3032 
3033  case OCLASS_TRIGGER:
3034  {
3035  Relation trigDesc;
3036  ScanKeyData skey[1];
3037  SysScanDesc tgscan;
3038  HeapTuple tup;
3039  Form_pg_trigger trig;
3040 
3042 
3043  ScanKeyInit(&skey[0],
3045  BTEqualStrategyNumber, F_OIDEQ,
3046  ObjectIdGetDatum(object->objectId));
3047 
3048  tgscan = systable_beginscan(trigDesc, TriggerOidIndexId, true,
3049  NULL, 1, skey);
3050 
3051  tup = systable_getnext(tgscan);
3052 
3053  if (!HeapTupleIsValid(tup))
3054  elog(ERROR, "could not find tuple for trigger %u",
3055  object->objectId);
3056 
3057  trig = (Form_pg_trigger) GETSTRUCT(tup);
3058 
3059  appendStringInfo(&buffer, _("trigger %s on "),
3060  NameStr(trig->tgname));
3061  getRelationDescription(&buffer, trig->tgrelid);
3062 
3063  systable_endscan(tgscan);
3064  heap_close(trigDesc, AccessShareLock);
3065  break;
3066  }
3067 
3068  case OCLASS_SCHEMA:
3069  {
3070  char *nspname;
3071 
3072  nspname = get_namespace_name(object->objectId);
3073  if (!nspname)
3074  elog(ERROR, "cache lookup failed for namespace %u",
3075  object->objectId);
3076  appendStringInfo(&buffer, _("schema %s"), nspname);
3077  break;
3078  }
3079 
3080  case OCLASS_STATISTIC_EXT:
3081  {
3082  HeapTuple stxTup;
3083  Form_pg_statistic_ext stxForm;
3084 
3085  stxTup = SearchSysCache1(STATEXTOID,
3086  ObjectIdGetDatum(object->objectId));
3087  if (!HeapTupleIsValid(stxTup))
3088  elog(ERROR, "could not find tuple for statistics object %u",
3089  object->objectId);
3090 
3091  stxForm = (Form_pg_statistic_ext) GETSTRUCT(stxTup);
3092 
3093  appendStringInfo(&buffer, _("statistics object %s"),
3094  NameStr(stxForm->stxname));
3095 
3096  ReleaseSysCache(stxTup);
3097  break;
3098  }
3099 
3100  case OCLASS_TSPARSER:
3101  {
3102  HeapTuple tup;
3103 
3105  ObjectIdGetDatum(object->objectId));
3106  if (!HeapTupleIsValid(tup))
3107  elog(ERROR, "cache lookup failed for text search parser %u",
3108  object->objectId);
3109  appendStringInfo(&buffer, _("text search parser %s"),
3110  NameStr(((Form_pg_ts_parser) GETSTRUCT(tup))->prsname));
3111  ReleaseSysCache(tup);
3112  break;
3113  }
3114 
3115  case OCLASS_TSDICT:
3116  {
3117  HeapTuple tup;
3118 
3119  tup = SearchSysCache1(TSDICTOID,
3120  ObjectIdGetDatum(object->objectId));
3121  if (!HeapTupleIsValid(tup))
3122  elog(ERROR, "cache lookup failed for text search dictionary %u",
3123  object->objectId);
3124  appendStringInfo(&buffer, _("text search dictionary %s"),
3125  NameStr(((Form_pg_ts_dict) GETSTRUCT(tup))->dictname));
3126  ReleaseSysCache(tup);
3127  break;
3128  }
3129 
3130  case OCLASS_TSTEMPLATE:
3131  {
3132  HeapTuple tup;
3133 
3135  ObjectIdGetDatum(object->objectId));
3136  if (!HeapTupleIsValid(tup))
3137  elog(ERROR, "cache lookup failed for text search template %u",
3138  object->objectId);
3139  appendStringInfo(&buffer, _("text search template %s"),
3140  NameStr(((Form_pg_ts_template) GETSTRUCT(tup))->tmplname));
3141  ReleaseSysCache(tup);
3142  break;
3143  }
3144 
3145  case OCLASS_TSCONFIG:
3146  {
3147  HeapTuple tup;
3148 
3150  ObjectIdGetDatum(object->objectId));
3151  if (!HeapTupleIsValid(tup))
3152  elog(ERROR, "cache lookup failed for text search configuration %u",
3153  object->objectId);
3154  appendStringInfo(&buffer, _("text search configuration %s"),
3155  NameStr(((Form_pg_ts_config) GETSTRUCT(tup))->cfgname));
3156  ReleaseSysCache(tup);
3157  break;
3158  }
3159 
3160  case OCLASS_ROLE:
3161  {
3162  appendStringInfo(&buffer, _("role %s"),
3163  GetUserNameFromId(object->objectId, false));
3164  break;
3165  }
3166 
3167  case OCLASS_DATABASE:
3168  {
3169  char *datname;
3170 
3171  datname = get_database_name(object->objectId);
3172  if (!datname)
3173  elog(ERROR, "cache lookup failed for database %u",
3174  object->objectId);
3175  appendStringInfo(&buffer, _("database %s"), datname);
3176  break;
3177  }
3178 
3179  case OCLASS_TBLSPACE:
3180  {
3181  char *tblspace;
3182 
3183  tblspace = get_tablespace_name(object->objectId);
3184  if (!tblspace)
3185  elog(ERROR, "cache lookup failed for tablespace %u",
3186  object->objectId);
3187  appendStringInfo(&buffer, _("tablespace %s"), tblspace);
3188  break;
3189  }
3190 
3191  case OCLASS_FDW:
3192  {
3193  ForeignDataWrapper *fdw;
3194 
3195  fdw = GetForeignDataWrapper(object->objectId);
3196  appendStringInfo(&buffer, _("foreign-data wrapper %s"), fdw->fdwname);
3197  break;
3198  }
3199 
3200  case OCLASS_FOREIGN_SERVER:
3201  {
3202  ForeignServer *srv;
3203 
3204  srv = GetForeignServer(object->objectId);
3205  appendStringInfo(&buffer, _("server %s"), srv->servername);
3206  break;
3207  }
3208 
3209  case OCLASS_USER_MAPPING:
3210  {
3211  HeapTuple tup;
3212  Oid useid;
3213  char *usename;
3214  Form_pg_user_mapping umform;
3215  ForeignServer *srv;
3216 
3218  ObjectIdGetDatum(object->objectId));
3219  if (!HeapTupleIsValid(tup))
3220  elog(ERROR, "cache lookup failed for user mapping %u",
3221  object->objectId);
3222  umform = (Form_pg_user_mapping) GETSTRUCT(tup);
3223  useid = umform->umuser;
3224  srv = GetForeignServer(umform->umserver);
3225 
3226  ReleaseSysCache(tup);
3227 
3228  if (OidIsValid(useid))
3229  usename = GetUserNameFromId(useid, false);
3230  else
3231  usename = "public";
3232 
3233  appendStringInfo(&buffer, _("user mapping for %s on server %s"), usename,
3234  srv->servername);
3235  break;
3236  }
3237 
3238  case OCLASS_DEFACL:
3239  {
3240  Relation defaclrel;
3241  ScanKeyData skey[1];
3242  SysScanDesc rcscan;
3243  HeapTuple tup;
3244  Form_pg_default_acl defacl;
3245 
3247 
3248  ScanKeyInit(&skey[0],
3250  BTEqualStrategyNumber, F_OIDEQ,
3251  ObjectIdGetDatum(object->objectId));
3252 
3253  rcscan = systable_beginscan(defaclrel, DefaultAclOidIndexId,
3254  true, NULL, 1, skey);
3255 
3256  tup = systable_getnext(rcscan);
3257 
3258  if (!HeapTupleIsValid(tup))
3259  elog(ERROR, "could not find tuple for default ACL %u",
3260  object->objectId);
3261 
3262  defacl = (Form_pg_default_acl) GETSTRUCT(tup);
3263 
3264  switch (defacl->defaclobjtype)
3265  {
3266  case DEFACLOBJ_RELATION:
3267  appendStringInfo(&buffer,
3268  _("default privileges on new relations belonging to role %s"),
3269  GetUserNameFromId(defacl->defaclrole, false));
3270  break;
3271  case DEFACLOBJ_SEQUENCE:
3272  appendStringInfo(&buffer,
3273  _("default privileges on new sequences belonging to role %s"),
3274  GetUserNameFromId(defacl->defaclrole, false));
3275  break;
3276  case DEFACLOBJ_FUNCTION:
3277  appendStringInfo(&buffer,
3278  _("default privileges on new functions belonging to role %s"),
3279  GetUserNameFromId(defacl->defaclrole, false));
3280  break;
3281  case DEFACLOBJ_TYPE:
3282  appendStringInfo(&buffer,
3283  _("default privileges on new types belonging to role %s"),
3284  GetUserNameFromId(defacl->defaclrole, false));
3285  break;
3286  case DEFACLOBJ_NAMESPACE:
3287  appendStringInfo(&buffer,
3288  _("default privileges on new schemas belonging to role %s"),
3289  GetUserNameFromId(defacl->defaclrole, false));
3290  break;
3291  default:
3292  /* shouldn't get here */
3293  appendStringInfo(&buffer,
3294  _("default privileges belonging to role %s"),
3295  GetUserNameFromId(defacl->defaclrole, false));
3296  break;
3297  }
3298 
3299  if (OidIsValid(defacl->defaclnamespace))
3300  {
3301  appendStringInfo(&buffer,
3302  _(" in schema %s"),
3303  get_namespace_name(defacl->defaclnamespace));
3304  }
3305 
3306  systable_endscan(rcscan);
3307  heap_close(defaclrel, AccessShareLock);
3308  break;
3309  }
3310 
3311  case OCLASS_EXTENSION:
3312  {
3313  char *extname;
3314 
3315  extname = get_extension_name(object->objectId);
3316  if (!extname)
3317  elog(ERROR, "cache lookup failed for extension %u",
3318  object->objectId);
3319  appendStringInfo(&buffer, _("extension %s"), extname);
3320  break;
3321  }
3322 
3323  case OCLASS_EVENT_TRIGGER:
3324  {
3325  HeapTuple tup;
3326 
3328  ObjectIdGetDatum(object->objectId));
3329  if (!HeapTupleIsValid(tup))
3330  elog(ERROR, "cache lookup failed for event trigger %u",
3331  object->objectId);
3332  appendStringInfo(&buffer, _("event trigger %s"),
3333  NameStr(((Form_pg_event_trigger) GETSTRUCT(tup))->evtname));
3334  ReleaseSysCache(tup);
3335  break;
3336  }
3337 
3338  case OCLASS_POLICY:
3339  {
3340  Relation policy_rel;
3341  ScanKeyData skey[1];
3342  SysScanDesc sscan;
3343  HeapTuple tuple;
3344  Form_pg_policy form_policy;
3345 
3347 
3348  ScanKeyInit(&skey[0],
3350  BTEqualStrategyNumber, F_OIDEQ,
3351  ObjectIdGetDatum(object->objectId));
3352 
3353  sscan = systable_beginscan(policy_rel, PolicyOidIndexId,
3354  true, NULL, 1, skey);
3355 
3356  tuple = systable_getnext(sscan);
3357 
3358  if (!HeapTupleIsValid(tuple))
3359  elog(ERROR, "could not find tuple for policy %u",
3360  object->objectId);
3361 
3362  form_policy = (Form_pg_policy) GETSTRUCT(tuple);
3363 
3364  appendStringInfo(&buffer, _("policy %s on "),
3365  NameStr(form_policy->polname));
3366  getRelationDescription(&buffer, form_policy->polrelid);
3367 
3368  systable_endscan(sscan);
3369  heap_close(policy_rel, AccessShareLock);
3370  break;
3371  }
3372 
3373  case OCLASS_PUBLICATION:
3374  {
3375  appendStringInfo(&buffer, _("publication %s"),
3376  get_publication_name(object->objectId));
3377  break;
3378  }
3379 
3381  {
3382  HeapTuple tup;
3383  char *pubname;
3384  Form_pg_publication_rel prform;
3385 
3387  ObjectIdGetDatum(object->objectId));
3388  if (!HeapTupleIsValid(tup))
3389  elog(ERROR, "cache lookup failed for publication table %u",
3390  object->objectId);
3391 
3392  prform = (Form_pg_publication_rel) GETSTRUCT(tup);
3393  pubname = get_publication_name(prform->prpubid);
3394 
3395  appendStringInfo(&buffer, _("publication table %s in publication %s"),
3396  get_rel_name(prform->prrelid), pubname);
3397  ReleaseSysCache(tup);
3398  break;
3399  }
3400 
3401  case OCLASS_SUBSCRIPTION:
3402  {
3403  appendStringInfo(&buffer, _("subscription %s"),
3404  get_subscription_name(object->objectId));
3405  break;
3406  }
3407 
3408  case OCLASS_TRANSFORM:
3409  {
3410  HeapTuple trfTup;
3411  Form_pg_transform trfForm;
3412 
3413  trfTup = SearchSysCache1(TRFOID,
3414  ObjectIdGetDatum(object->objectId));
3415  if (!HeapTupleIsValid(trfTup))
3416  elog(ERROR, "could not find tuple for transform %u",
3417  object->objectId);
3418 
3419  trfForm = (Form_pg_transform) GETSTRUCT(trfTup);
3420 
3421  appendStringInfo(&buffer, _("transform for %s language %s"),
3422  format_type_be(trfForm->trftype),
3423  get_language_name(trfForm->trflang, false));
3424 
3425  ReleaseSysCache(trfTup);
3426  break;
3427  }
3428 
3429  /*
3430  * There's intentionally no default: case here; we want the
3431  * compiler to warn if a new OCLASS hasn't been handled above.
3432  */
3433  }
3434 
3435  return buffer.data;
3436 }
3437 
3438 /*
3439  * getObjectDescriptionOids: as above, except the object is specified by Oids
3440  */
3441 char *
3443 {
3444  ObjectAddress address;
3445 
3446  address.classId = classid;
3447  address.objectId = objid;
3448  address.objectSubId = 0;
3449 
3450  return getObjectDescription(&address);
3451 }
3452 
3453 /*
3454  * subroutine for getObjectDescription: describe a relation
3455  */
3456 static void
3458 {
3459  HeapTuple relTup;
3460  Form_pg_class relForm;
3461  char *nspname;
3462  char *relname;
3463 
3464  relTup = SearchSysCache1(RELOID,
3465  ObjectIdGetDatum(relid));
3466  if (!HeapTupleIsValid(relTup))
3467  elog(ERROR, "cache lookup failed for relation %u", relid);
3468  relForm = (Form_pg_class) GETSTRUCT(relTup);
3469 
3470  /* Qualify the name if not visible in search path */
3471  if (RelationIsVisible(relid))
3472  nspname = NULL;
3473  else
3474  nspname = get_namespace_name(relForm->relnamespace);
3475 
3476  relname = quote_qualified_identifier(nspname, NameStr(relForm->relname));
3477 
3478  switch (relForm->relkind)
3479  {
3480  case RELKIND_RELATION:
3482  appendStringInfo(buffer, _("table %s"),
3483  relname);
3484  break;
3485  case RELKIND_INDEX:
3486  appendStringInfo(buffer, _("index %s"),
3487  relname);
3488  break;
3489  case RELKIND_SEQUENCE:
3490  appendStringInfo(buffer, _("sequence %s"),
3491  relname);
3492  break;
3493  case RELKIND_TOASTVALUE:
3494  appendStringInfo(buffer, _("toast table %s"),
3495  relname);
3496  break;
3497  case RELKIND_VIEW:
3498  appendStringInfo(buffer, _("view %s"),
3499  relname);
3500  break;
3501  case RELKIND_MATVIEW:
3502  appendStringInfo(buffer, _("materialized view %s"),
3503  relname);
3504  break;
3506  appendStringInfo(buffer, _("composite type %s"),
3507  relname);
3508  break;
3509  case RELKIND_FOREIGN_TABLE:
3510  appendStringInfo(buffer, _("foreign table %s"),
3511  relname);
3512  break;
3513  default:
3514  /* shouldn't get here */
3515  appendStringInfo(buffer, _("relation %s"),
3516  relname);
3517  break;
3518  }
3519 
3520  ReleaseSysCache(relTup);
3521 }
3522 
3523 /*
3524  * subroutine for getObjectDescription: describe an operator family
3525  */
3526 static void
3528 {
3529  HeapTuple opfTup;
3530  Form_pg_opfamily opfForm;
3531  HeapTuple amTup;
3532  Form_pg_am amForm;
3533  char *nspname;
3534 
3535  opfTup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfid));
3536  if (!HeapTupleIsValid(opfTup))
3537  elog(ERROR, "cache lookup failed for opfamily %u", opfid);
3538  opfForm = (Form_pg_opfamily) GETSTRUCT(opfTup);
3539 
3540  amTup = SearchSysCache1(AMOID, ObjectIdGetDatum(opfForm->opfmethod));
3541  if (!HeapTupleIsValid(amTup))
3542  elog(ERROR, "cache lookup failed for access method %u",
3543  opfForm->opfmethod);
3544  amForm = (Form_pg_am) GETSTRUCT(amTup);
3545 
3546  /* Qualify the name if not visible in search path */
3547  if (OpfamilyIsVisible(opfid))
3548  nspname = NULL;
3549  else
3550  nspname = get_namespace_name(opfForm->opfnamespace);
3551 
3552  appendStringInfo(buffer, _("operator family %s for access method %s"),
3554  NameStr(opfForm->opfname)),
3555  NameStr(amForm->amname));
3556 
3557  ReleaseSysCache(amTup);
3558  ReleaseSysCache(opfTup);
3559 }
3560 
3561 /*
3562  * SQL-level callable version of getObjectDescription
3563  */
3564 Datum
3566 {
3567  Oid classid = PG_GETARG_OID(0);
3568  Oid objid = PG_GETARG_OID(1);
3569  int32 objsubid = PG_GETARG_INT32(2);
3570  char *description;
3571  ObjectAddress address;
3572 
3573  /* for "pinned" items in pg_depend, return null */
3574  if (!OidIsValid(classid) && !OidIsValid(objid))
3575  PG_RETURN_NULL();
3576 
3577  address.classId = classid;
3578  address.objectId = objid;
3579  address.objectSubId = objsubid;
3580 
3581  description = getObjectDescription(&address);
3582  PG_RETURN_TEXT_P(cstring_to_text(description));
3583 }
3584 
3585 /*
3586  * SQL-level callable function to obtain object type + identity
3587  */
3588 Datum
3590 {
3591  Oid classid = PG_GETARG_OID(0);
3592  Oid objid = PG_GETARG_OID(1);
3593  int32 objsubid = PG_GETARG_INT32(2);
3594  Oid schema_oid = InvalidOid;
3595  const char *objname = NULL;
3596  ObjectAddress address;
3597  Datum values[4];
3598  bool nulls[4];
3599  TupleDesc tupdesc;
3600  HeapTuple htup;
3601 
3602  address.classId = classid;
3603  address.objectId = objid;
3604  address.objectSubId = objsubid;
3605 
3606  /*
3607  * Construct a tuple descriptor for the result row. This must match this
3608  * function's pg_proc entry!
3609  */
3610  tupdesc = CreateTemplateTupleDesc(4, false);
3611  TupleDescInitEntry(tupdesc, (AttrNumber) 1, "type",
3612  TEXTOID, -1, 0);
3613  TupleDescInitEntry(tupdesc, (AttrNumber) 2, "schema",
3614  TEXTOID, -1, 0);
3615  TupleDescInitEntry(tupdesc, (AttrNumber) 3, "name",
3616  TEXTOID, -1, 0);
3617  TupleDescInitEntry(tupdesc, (AttrNumber) 4, "identity",
3618  TEXTOID, -1, 0);
3619 
3620  tupdesc = BlessTupleDesc(tupdesc);
3621 
3622  if (is_objectclass_supported(address.classId))
3623  {
3624  HeapTuple objtup;
3625  Relation catalog = heap_open(address.classId, AccessShareLock);
3626 
3627  objtup = get_catalog_object_by_oid(catalog, address.objectId);
3628  if (objtup != NULL)
3629  {
3630  bool isnull;
3631  AttrNumber nspAttnum;
3632  AttrNumber nameAttnum;
3633 
3634  nspAttnum = get_object_attnum_namespace(address.classId);
3635  if (nspAttnum != InvalidAttrNumber)
3636  {
3637  schema_oid = heap_getattr(objtup, nspAttnum,
3638  RelationGetDescr(catalog), &isnull);
3639  if (isnull)
3640  elog(ERROR, "invalid null namespace in object %u/%u/%d",
3641  address.classId, address.objectId, address.objectSubId);
3642  }
3643 
3644  /*
3645  * We only return the object name if it can be used (together with
3646  * the schema name, if any) as a unique identifier.
3647  */
3648  if (get_object_namensp_unique(address.classId))
3649  {
3650  nameAttnum = get_object_attnum_name(address.classId);
3651  if (nameAttnum != InvalidAttrNumber)
3652  {
3653  Datum nameDatum;
3654 
3655  nameDatum = heap_getattr(objtup, nameAttnum,
3656  RelationGetDescr(catalog), &isnull);
3657  if (isnull)
3658  elog(ERROR, "invalid null name in object %u/%u/%d",
3659  address.classId, address.objectId, address.objectSubId);
3660  objname = quote_identifier(NameStr(*(DatumGetName(nameDatum))));
3661  }
3662  }
3663  }
3664 
3665  heap_close(catalog, AccessShareLock);
3666  }
3667 
3668  /* object type */
3669  values[0] = CStringGetTextDatum(getObjectTypeDescription(&address));
3670  nulls[0] = false;
3671 
3672  /* schema name */
3673  if (OidIsValid(schema_oid))
3674  {
3675  const char *schema = quote_identifier(get_namespace_name(schema_oid));
3676 
3677  values[1] = CStringGetTextDatum(schema);
3678  nulls[1] = false;
3679  }
3680  else
3681  nulls[1] = true;
3682 
3683  /* object name */
3684  if (objname)
3685  {
3686  values[2] = CStringGetTextDatum(objname);
3687  nulls[2] = false;
3688  }
3689  else
3690  nulls[2] = true;
3691 
3692  /* object identity */
3693  values[3] = CStringGetTextDatum(getObjectIdentity(&address));
3694  nulls[3] = false;
3695 
3696  htup = heap_form_tuple(tupdesc, values, nulls);
3697 
3699 }
3700 
3701 /*
3702  * SQL-level callable function to obtain object type + identity
3703  */
3704 Datum
3706 {
3707  Oid classid = PG_GETARG_OID(0);
3708  Oid objid = PG_GETARG_OID(1);
3709  int32 objsubid = PG_GETARG_INT32(2);
3710  ObjectAddress address;
3711  char *identity;
3712  List *names;
3713  List *args;
3714  Datum values[3];
3715  bool nulls[3];
3716  TupleDesc tupdesc;
3717  HeapTuple htup;
3718 
3719  address.classId = classid;
3720  address.objectId = objid;
3721  address.objectSubId = objsubid;
3722 
3723  /*
3724  * Construct a tuple descriptor for the result row. This must match this
3725  * function's pg_proc entry!
3726  */
3727  tupdesc = CreateTemplateTupleDesc(3, false);
3728  TupleDescInitEntry(tupdesc, (AttrNumber) 1, "type",
3729  TEXTOID, -1, 0);
3730  TupleDescInitEntry(tupdesc, (AttrNumber) 2, "object_names",
3731  TEXTARRAYOID, -1, 0);
3732  TupleDescInitEntry(tupdesc, (AttrNumber) 3, "object_args",
3733  TEXTARRAYOID, -1, 0);
3734 
3735  tupdesc = BlessTupleDesc(tupdesc);
3736 
3737  /* object type */
3738  values[0] = CStringGetTextDatum(getObjectTypeDescription(&address));
3739  nulls[0] = false;
3740 
3741  /* object identity */
3742  identity = getObjectIdentityParts(&address, &names, &args);
3743  pfree(identity);
3744 
3745  /* object_names */
3746  values[1] = PointerGetDatum(strlist_to_textarray(names));
3747  nulls[1] = false;
3748 
3749  /* object_args */
3750  if (args)
3751  values[2] = PointerGetDatum(strlist_to_textarray(args));
3752  else
3754  nulls[2] = false;
3755 
3756  htup = heap_form_tuple(tupdesc, values, nulls);
3757 
3759 }
3760 
3761 /*
3762  * Return a palloc'ed string that describes the type of object that the
3763  * passed address is for.
3764  *
3765  * Keep ObjectTypeMap in sync with this.
3766  */
3767 char *
3769 {
3771 
3772  initStringInfo(&buffer);
3773 
3774  switch (getObjectClass(object))
3775  {
3776  case OCLASS_CLASS:
3777  getRelationTypeDescription(&buffer, object->objectId,
3778  object->objectSubId);
3779  break;
3780 
3781  case OCLASS_PROC:
3782  getProcedureTypeDescription(&buffer, object->objectId);
3783  break;
3784 
3785  case OCLASS_TYPE:
3786  appendStringInfoString(&buffer, "type");
3787  break;
3788 
3789  case OCLASS_CAST:
3790  appendStringInfoString(&buffer, "cast");
3791  break;
3792 
3793  case OCLASS_COLLATION:
3794  appendStringInfoString(&buffer, "collation");
3795  break;
3796 
3797  case OCLASS_CONSTRAINT:
3798  getConstraintTypeDescription(&buffer, object->objectId);
3799  break;
3800 
3801  case OCLASS_CONVERSION:
3802  appendStringInfoString(&buffer, "conversion");
3803  break;
3804 
3805  case OCLASS_DEFAULT:
3806  appendStringInfoString(&buffer, "default value");
3807  break;
3808 
3809  case OCLASS_LANGUAGE:
3810  appendStringInfoString(&buffer, "language");
3811  break;
3812 
3813  case OCLASS_LARGEOBJECT:
3814  appendStringInfoString(&buffer, "large object");
3815  break;
3816 
3817  case OCLASS_OPERATOR:
3818  appendStringInfoString(&buffer, "operator");
3819  break;
3820 
3821  case OCLASS_OPCLASS:
3822  appendStringInfoString(&buffer, "operator class");
3823  break;
3824 
3825  case OCLASS_OPFAMILY:
3826  appendStringInfoString(&buffer, "operator family");
3827  break;
3828 
3829  case OCLASS_AM:
3830  appendStringInfoString(&buffer, "access method");
3831  break;
3832 
3833  case OCLASS_AMOP:
3834  appendStringInfoString(&buffer, "operator of access method");
3835  break;
3836 
3837  case OCLASS_AMPROC:
3838  appendStringInfoString(&buffer, "function of access method");
3839  break;
3840 
3841  case OCLASS_REWRITE:
3842  appendStringInfoString(&buffer, "rule");
3843  break;
3844 
3845  case OCLASS_TRIGGER:
3846  appendStringInfoString(&buffer, "trigger");
3847  break;
3848 
3849  case OCLASS_SCHEMA:
3850  appendStringInfoString(&buffer, "schema");
3851  break;
3852 
3853  case OCLASS_STATISTIC_EXT:
3854  appendStringInfoString(&buffer, "statistics object");
3855  break;
3856 
3857  case OCLASS_TSPARSER:
3858  appendStringInfoString(&buffer, "text search parser");
3859  break;
3860 
3861  case OCLASS_TSDICT:
3862  appendStringInfoString(&buffer, "text search dictionary");
3863  break;
3864 
3865  case OCLASS_TSTEMPLATE:
3866  appendStringInfoString(&buffer, "text search template");
3867  break;
3868 
3869  case OCLASS_TSCONFIG:
3870  appendStringInfoString(&buffer, "text search configuration");
3871  break;
3872 
3873  case OCLASS_ROLE:
3874  appendStringInfoString(&buffer, "role");
3875  break;
3876 
3877  case OCLASS_DATABASE:
3878  appendStringInfoString(&buffer, "database");
3879  break;
3880 
3881  case OCLASS_TBLSPACE:
3882  appendStringInfoString(&buffer, "tablespace");
3883  break;
3884 
3885  case OCLASS_FDW:
3886  appendStringInfoString(&buffer, "foreign-data wrapper");
3887  break;
3888 
3889  case OCLASS_FOREIGN_SERVER:
3890  appendStringInfoString(&buffer, "server");
3891  break;
3892 
3893  case OCLASS_USER_MAPPING:
3894  appendStringInfoString(&buffer, "user mapping");
3895  break;
3896 
3897  case OCLASS_DEFACL:
3898  appendStringInfoString(&buffer, "default acl");
3899  break;
3900 
3901  case OCLASS_EXTENSION:
3902  appendStringInfoString(&buffer, "extension");
3903  break;
3904 
3905  case OCLASS_EVENT_TRIGGER:
3906  appendStringInfoString(&buffer, "event trigger");
3907  break;
3908 
3909  case OCLASS_POLICY:
3910  appendStringInfoString(&buffer, "policy");
3911  break;
3912 
3913  case OCLASS_PUBLICATION:
3914  appendStringInfoString(&buffer, "publication");
3915  break;
3916 
3918  appendStringInfoString(&buffer, "publication relation");
3919  break;
3920 
3921  case OCLASS_SUBSCRIPTION:
3922  appendStringInfoString(&buffer, "subscription");
3923  break;
3924 
3925  case OCLASS_TRANSFORM:
3926  appendStringInfoString(&buffer, "transform");
3927  break;
3928 
3929  /*
3930  * There's intentionally no default: case here; we want the
3931  * compiler to warn if a new OCLASS hasn't been handled above.
3932  */
3933  }
3934 
3935  return buffer.data;
3936 }
3937 
3938 /*
3939  * subroutine for getObjectTypeDescription: describe a relation type
3940  */
3941 static void
3942 getRelationTypeDescription(StringInfo buffer, Oid relid, int32 objectSubId)
3943 {
3944  HeapTuple relTup;
3945  Form_pg_class relForm;
3946 
3947  relTup = SearchSysCache1(RELOID,
3948  ObjectIdGetDatum(relid));
3949  if (!HeapTupleIsValid(relTup))
3950  elog(ERROR, "cache lookup failed for relation %u", relid);
3951  relForm = (Form_pg_class) GETSTRUCT(relTup);
3952 
3953  switch (relForm->relkind)
3954  {
3955  case RELKIND_RELATION:
3957  appendStringInfoString(buffer, "table");
3958  break;
3959  case RELKIND_INDEX:
3960  appendStringInfoString(buffer, "index");
3961  break;
3962  case RELKIND_SEQUENCE:
3963  appendStringInfoString(buffer, "sequence");
3964  break;
3965  case RELKIND_TOASTVALUE:
3966  appendStringInfoString(buffer, "toast table");
3967  break;
3968  case RELKIND_VIEW:
3969  appendStringInfoString(buffer, "view");
3970  break;
3971  case RELKIND_MATVIEW:
3972  appendStringInfoString(buffer, "materialized view");
3973  break;
3975  appendStringInfoString(buffer, "composite type");
3976  break;
3977  case RELKIND_FOREIGN_TABLE:
3978  appendStringInfoString(buffer, "foreign table");
3979  break;
3980  default:
3981  /* shouldn't get here */
3982  appendStringInfoString(buffer, "relation");
3983  break;
3984  }
3985 
3986  if (objectSubId != 0)
3987  appendStringInfoString(buffer, " column");
3988 
3989  ReleaseSysCache(relTup);
3990 }
3991 
3992 /*
3993  * subroutine for getObjectTypeDescription: describe a constraint type
3994  */
3995 static void
3997 {
3998  Relation constrRel;
3999  HeapTuple constrTup;
4000  Form_pg_constraint constrForm;
4001 
4003  constrTup = get_catalog_object_by_oid(constrRel, constroid);
4004  if (!HeapTupleIsValid(constrTup))
4005  elog(ERROR, "cache lookup failed for constraint %u", constroid);
4006 
4007  constrForm = (Form_pg_constraint) GETSTRUCT(constrTup);
4008 
4009  if (OidIsValid(constrForm->conrelid))
4010  appendStringInfoString(buffer, "table constraint");
4011  else if (OidIsValid(constrForm->contypid))
4012  appendStringInfoString(buffer, "domain constraint");
4013  else
4014  elog(ERROR, "invalid constraint %u", HeapTupleGetOid(constrTup));
4015 
4016  heap_close(constrRel, AccessShareLock);
4017 }
4018 
4019 /*
4020  * subroutine for getObjectTypeDescription: describe a procedure type
4021  */
4022 static void
4024 {
4025  HeapTuple procTup;
4026  Form_pg_proc procForm;
4027 
4028  procTup = SearchSysCache1(PROCOID,
4029  ObjectIdGetDatum(procid));
4030  if (!HeapTupleIsValid(procTup))
4031  elog(ERROR, "cache lookup failed for procedure %u", procid);
4032  procForm = (Form_pg_proc) GETSTRUCT(procTup);
4033 
4034  if (procForm->proisagg)
4035  appendStringInfoString(buffer, "aggregate");
4036  else if (procForm->prorettype == InvalidOid)
4037  appendStringInfoString(buffer, "procedure");
4038  else
4039  appendStringInfoString(buffer, "function");
4040 
4041  ReleaseSysCache(procTup);
4042 }
4043 
4044 /*
4045  * Obtain a given object's identity, as a palloc'ed string.
4046  *
4047  * This is for machine consumption, so it's not translated. All elements are
4048  * schema-qualified when appropriate.
4049  */
4050 char *
4052 {
4053  return getObjectIdentityParts(object, NULL, NULL);
4054 }
4055 
4056 /*
4057  * As above, but more detailed.
4058  *
4059  * There are two sets of return values: the identity itself as a palloc'd
4060  * string is returned. objname and objargs, if not NULL, are output parameters
4061  * that receive lists of C-strings that are useful to give back to
4062  * get_object_address() to reconstruct the ObjectAddress.
4063  */
4064 char *
4066  List **objname, List **objargs)
4067 {
4069 
4070  initStringInfo(&buffer);
4071 
4072  /*
4073  * Make sure that both objname and objargs were passed, or none was; and
4074  * initialize them to empty lists. For objname this is useless because it
4075  * will be initialized in all cases inside the switch; but we do it anyway
4076  * so that we can test below that no branch leaves it unset.
4077  */
4078  Assert(PointerIsValid(objname) == PointerIsValid(objargs));
4079  if (objname)
4080  {
4081  *objname = NIL;
4082  *objargs = NIL;
4083  }
4084 
4085  switch (getObjectClass(object))
4086  {
4087  case OCLASS_CLASS:
4088  getRelationIdentity(&buffer, object->objectId, objname);
4089  if (object->objectSubId != 0)
4090  {
4091  char *attr;
4092 
4093  attr = get_relid_attribute_name(object->objectId,
4094  object->objectSubId);
4095  appendStringInfo(&buffer, ".%s", quote_identifier(attr));
4096  if (objname)
4097  *objname = lappend(*objname, attr);
4098  }
4099  break;
4100 
4101  case OCLASS_PROC:
4102  appendStringInfoString(&buffer,
4104  if (objname)
4105  format_procedure_parts(object->objectId, objname, objargs);
4106  break;
4107 
4108  case OCLASS_TYPE:
4109  {
4110  char *typeout;
4111 
4112  typeout = format_type_be_qualified(object->objectId);
4113  appendStringInfoString(&buffer, typeout);
4114  if (objname)
4115  *objname = list_make1(typeout);
4116  }
4117  break;
4118 
4119  case OCLASS_CAST:
4120  {
4121  Relation castRel;
4122  HeapTuple tup;
4123  Form_pg_cast castForm;
4124 
4126 
4127  tup = get_catalog_object_by_oid(castRel, object->objectId);
4128 
4129  if (!HeapTupleIsValid(tup))
4130  elog(ERROR, "could not find tuple for cast %u",
4131  object->objectId);
4132 
4133  castForm = (Form_pg_cast) GETSTRUCT(tup);
4134 
4135  appendStringInfo(&buffer, "(%s AS %s)",
4136  format_type_be_qualified(castForm->castsource),
4137  format_type_be_qualified(castForm->casttarget));
4138 
4139  if (objname)
4140  {
4141  *objname = list_make1(format_type_be_qualified(castForm->castsource));
4142  *objargs = list_make1(format_type_be_qualified(castForm->casttarget));
4143  }
4144 
4145  heap_close(castRel, AccessShareLock);
4146  break;
4147  }
4148 
4149  case OCLASS_COLLATION:
4150  {
4151  HeapTuple collTup;
4152  Form_pg_collation coll;
4153  char *schema;
4154 
4155  collTup = SearchSysCache1(COLLOID,
4156  ObjectIdGetDatum(object->objectId));
4157  if (!HeapTupleIsValid(collTup))
4158  elog(ERROR, "cache lookup failed for collation %u",
4159  object->objectId);
4160  coll = (Form_pg_collation) GETSTRUCT(collTup);
4161  schema = get_namespace_name_or_temp(coll->collnamespace);
4162  appendStringInfoString(&buffer,
4164  NameStr(coll->collname)));
4165  if (objname)
4166  *objname = list_make2(schema,
4167  pstrdup(NameStr(coll->collname)));
4168  ReleaseSysCache(collTup);
4169  break;
4170  }
4171 
4172  case OCLASS_CONSTRAINT:
4173  {
4174  HeapTuple conTup;
4175  Form_pg_constraint con;
4176 
4177  conTup = SearchSysCache1(CONSTROID,
4178  ObjectIdGetDatum(object->objectId));
4179  if (!HeapTupleIsValid(conTup))
4180  elog(ERROR, "cache lookup failed for constraint %u",
4181  object->objectId);
4182  con = (Form_pg_constraint) GETSTRUCT(conTup);
4183 
4184  if (OidIsValid(con->conrelid))
4185  {
4186  appendStringInfo(&buffer, "%s on ",
4187  quote_identifier(NameStr(con->conname)));
4188  getRelationIdentity(&buffer, con->conrelid, objname);
4189  if (objname)
4190  *objname = lappend(*objname, pstrdup(NameStr(con->conname)));
4191  }
4192  else
4193  {
4194  ObjectAddress domain;
4195 
4196  Assert(OidIsValid(con->contypid));
4197  domain.classId = TypeRelationId;
4198  domain.objectId = con->contypid;
4199  domain.objectSubId = 0;
4200 
4201  appendStringInfo(&buffer, "%s on %s",
4202  quote_identifier(NameStr(con->conname)),
4203  getObjectIdentityParts(&domain, objname, objargs));
4204 
4205  if (objname)
4206  *objargs = lappend(*objargs, pstrdup(NameStr(con->conname)));
4207  }
4208 
4209  ReleaseSysCache(conTup);
4210  break;
4211  }
4212 
4213  case OCLASS_CONVERSION:
4214  {
4215  HeapTuple conTup;
4216  Form_pg_conversion conForm;
4217  char *schema;
4218 
4219  conTup = SearchSysCache1(CONVOID,
4220  ObjectIdGetDatum(object->objectId));
4221  if (!HeapTupleIsValid(conTup))
4222  elog(ERROR, "cache lookup failed for conversion %u",
4223  object->objectId);
4224  conForm = (Form_pg_conversion) GETSTRUCT(conTup);
4225  schema = get_namespace_name_or_temp(conForm->connamespace);
4226  appendStringInfoString(&buffer,
4228  NameStr(conForm->conname)));
4229  if (objname)
4230  *objname = list_make2(schema,
4231  pstrdup(NameStr(conForm->conname)));
4232  ReleaseSysCache(conTup);
4233  break;
4234  }
4235 
4236  case OCLASS_DEFAULT:
4237  {
4238  Relation attrdefDesc;
4239  ScanKeyData skey[1];
4240  SysScanDesc adscan;
4241 
4242  HeapTuple tup;
4243  Form_pg_attrdef attrdef;
4244  ObjectAddress colobject;
4245 
4247 
4248  ScanKeyInit(&skey[0],
4250  BTEqualStrategyNumber, F_OIDEQ,
4251  ObjectIdGetDatum(object->objectId));
4252 
4253  adscan = systable_beginscan(attrdefDesc, AttrDefaultOidIndexId,
4254  true, NULL, 1, skey);
4255 
4256  tup = systable_getnext(adscan);
4257 
4258  if (!HeapTupleIsValid(tup))
4259  elog(ERROR, "could not find tuple for attrdef %u",
4260  object->objectId);
4261 
4262  attrdef = (Form_pg_attrdef) GETSTRUCT(tup);
4263 
4264  colobject.classId = RelationRelationId;
4265  colobject.objectId = attrdef->adrelid;
4266  colobject.objectSubId = attrdef->adnum;
4267 
4268  appendStringInfo(&buffer, "for %s",
4269  getObjectIdentityParts(&colobject,
4270  objname, objargs));
4271 
4272  systable_endscan(adscan);
4273  heap_close(attrdefDesc, AccessShareLock);
4274  break;
4275  }
4276 
4277  case OCLASS_LANGUAGE:
4278  {
4279  HeapTuple langTup;
4280  Form_pg_language langForm;
4281 
4282  langTup = SearchSysCache1(LANGOID,
4283  ObjectIdGetDatum(object->objectId));
4284  if (!HeapTupleIsValid(langTup))
4285  elog(ERROR, "cache lookup failed for language %u",
4286  object->objectId);
4287  langForm = (Form_pg_language) GETSTRUCT(langTup);
4288  appendStringInfoString(&buffer,
4289  quote_identifier(NameStr(langForm->lanname)));
4290  if (objname)
4291  *objname = list_make1(pstrdup(NameStr(langForm->lanname)));
4292  ReleaseSysCache(langTup);
4293  break;
4294  }
4295  case OCLASS_LARGEOBJECT:
4296  appendStringInfo(&buffer, "%u",
4297  object->objectId);
4298  if (objname)
4299  *objname = list_make1(psprintf("%u", object->objectId));
4300  break;
4301 
4302  case OCLASS_OPERATOR:
4303  appendStringInfoString(&buffer,
4305  if (objname)
4306  format_operator_parts(object->objectId, objname, objargs);
4307  break;
4308 
4309  case OCLASS_OPCLASS:
4310  {
4311  HeapTuple opcTup;
4312  Form_pg_opclass opcForm;
4313  HeapTuple amTup;
4314  Form_pg_am amForm;
4315  char *schema;
4316 
4317  opcTup = SearchSysCache1(CLAOID,
4318  ObjectIdGetDatum(object->objectId));
4319  if (!HeapTupleIsValid(opcTup))
4320  elog(ERROR, "cache lookup failed for opclass %u",
4321  object->objectId);
4322  opcForm = (Form_pg_opclass) GETSTRUCT(opcTup);
4323  schema = get_namespace_name_or_temp(opcForm->opcnamespace);
4324 
4325  amTup = SearchSysCache1(AMOID,
4326  ObjectIdGetDatum(opcForm->opcmethod));
4327  if (!HeapTupleIsValid(amTup))
4328  elog(ERROR, "cache lookup failed for access method %u",
4329  opcForm->opcmethod);
4330  amForm = (Form_pg_am) GETSTRUCT(amTup);
4331 
4332  appendStringInfo(&buffer, "%s USING %s",
4334  NameStr(opcForm->opcname)),
4335  quote_identifier(NameStr(amForm->amname)));
4336  if (objname)
4337  *objname = list_make3(pstrdup(NameStr(amForm->amname)),
4338  schema,
4339  pstrdup(NameStr(opcForm->opcname)));
4340 
4341  ReleaseSysCache(amTup);
4342  ReleaseSysCache(opcTup);
4343  break;
4344  }
4345 
4346  case OCLASS_OPFAMILY:
4347  getOpFamilyIdentity(&buffer, object->objectId, objname);
4348  break;
4349 
4350  case OCLASS_AM:
4351  {
4352  char *amname;
4353 
4354  amname = get_am_name(object->objectId);
4355  if (!amname)
4356  elog(ERROR, "cache lookup failed for access method %u",
4357  object->objectId);
4358  appendStringInfoString(&buffer, quote_identifier(amname));
4359  if (objname)
4360  *objname = list_make1(amname);
4361  }
4362  break;
4363 
4364  case OCLASS_AMOP:
4365  {
4366  Relation amopDesc;
4367  HeapTuple tup;
4368  ScanKeyData skey[1];
4369  SysScanDesc amscan;
4370  Form_pg_amop amopForm;
4371  StringInfoData opfam;
4372  char *ltype;
4373  char *rtype;
4374 
4376  AccessShareLock);
4377 
4378  ScanKeyInit(&skey[0],
4380  BTEqualStrategyNumber, F_OIDEQ,
4381  ObjectIdGetDatum(object->objectId));
4382 
4383  amscan = systable_beginscan(amopDesc, AccessMethodOperatorOidIndexId, true,
4384  NULL, 1, skey);
4385 
4386  tup = systable_getnext(amscan);
4387 
4388  if (!HeapTupleIsValid(tup))
4389  elog(ERROR, "could not find tuple for amop entry %u",
4390  object->objectId);
4391 
4392  amopForm = (Form_pg_amop) GETSTRUCT(tup);
4393 
4394  initStringInfo(&opfam);
4395  getOpFamilyIdentity(&opfam, amopForm->amopfamily, objname);
4396 
4397  ltype = format_type_be_qualified(amopForm->amoplefttype);
4398  rtype = format_type_be_qualified(amopForm->amoprighttype);
4399 
4400  if (objname)
4401  {
4402  *objname = lappend(*objname,
4403  psprintf("%d", amopForm->amopstrategy));
4404  *objargs = list_make2(ltype, rtype);
4405  }
4406 
4407  appendStringInfo(&buffer, "operator %d (%s, %s) of %s",
4408  amopForm->amopstrategy,
4409  ltype, rtype, opfam.data);
4410 
4411  pfree(opfam.data);
4412 
4413  systable_endscan(amscan);
4414  heap_close(amopDesc, AccessShareLock);
4415  break;
4416  }
4417 
4418  case OCLASS_AMPROC:
4419  {
4420  Relation amprocDesc;
4421  ScanKeyData skey[1];
4422  SysScanDesc amscan;
4423  HeapTuple tup;
4424  Form_pg_amproc amprocForm;
4425  StringInfoData opfam;
4426  char *ltype;
4427  char *rtype;
4428 
4430  AccessShareLock);
4431 
4432  ScanKeyInit(&skey[0],
4434  BTEqualStrategyNumber, F_OIDEQ,
4435  ObjectIdGetDatum(object->objectId));
4436 
4437  amscan = systable_beginscan(amprocDesc, AccessMethodProcedureOidIndexId, true,
4438  NULL, 1, skey);
4439 
4440  tup = systable_getnext(amscan);
4441 
4442  if (!HeapTupleIsValid(tup))
4443  elog(ERROR, "could not find tuple for amproc entry %u",
4444  object->objectId);
4445 
4446  amprocForm = (Form_pg_amproc) GETSTRUCT(tup);
4447 
4448  initStringInfo(&opfam);
4449  getOpFamilyIdentity(&opfam, amprocForm->amprocfamily, objname);
4450 
4451  ltype = format_type_be_qualified(amprocForm->amproclefttype);
4452  rtype = format_type_be_qualified(amprocForm->amprocrighttype);
4453 
4454  if (objname)
4455  {
4456  *objname = lappend(*objname,
4457  psprintf("%d", amprocForm->amprocnum));
4458  *objargs = list_make2(ltype, rtype);
4459  }
4460 
4461  appendStringInfo(&buffer, "function %d (%s, %s) of %s",
4462  amprocForm->amprocnum,
4463  ltype, rtype, opfam.data);
4464 
4465  pfree(opfam.data);
4466 
4467  systable_endscan(amscan);
4468  heap_close(amprocDesc, AccessShareLock);
4469  break;
4470  }
4471 
4472  case OCLASS_REWRITE:
4473  {
4474  Relation ruleDesc;
4475  HeapTuple tup;
4477 
4479 
4480  tup = get_catalog_object_by_oid(ruleDesc, object->objectId);
4481 
4482  if (!HeapTupleIsValid(tup))
4483  elog(ERROR, "could not find tuple for rule %u",
4484  object->objectId);
4485 
4486  rule = (Form_pg_rewrite) GETSTRUCT(tup);
4487 
4488  appendStringInfo(&buffer, "%s on ",
4489  quote_identifier(NameStr(rule->rulename)));
4490  getRelationIdentity(&buffer, rule->ev_class, objname);
4491  if (objname)
4492  *objname = lappend(*objname, pstrdup(NameStr(rule->rulename)));
4493 
4494  heap_close(ruleDesc, AccessShareLock);
4495  break;
4496  }
4497 
4498  case OCLASS_TRIGGER:
4499  {
4500  Relation trigDesc;
4501  HeapTuple tup;
4502  Form_pg_trigger trig;
4503 
4505 
4506  tup = get_catalog_object_by_oid(trigDesc, object->objectId);
4507 
4508  if (!HeapTupleIsValid(tup))
4509  elog(ERROR, "could not find tuple for trigger %u",
4510  object->objectId);
4511 
4512  trig = (Form_pg_trigger) GETSTRUCT(tup);
4513 
4514  appendStringInfo(&buffer, "%s on ",
4515  quote_identifier(NameStr(trig->tgname)));
4516  getRelationIdentity(&buffer, trig->tgrelid, objname);
4517  if (objname)
4518  *objname = lappend(*objname, pstrdup(NameStr(trig->tgname)));
4519 
4520  heap_close(trigDesc, AccessShareLock);
4521  break;
4522  }
4523 
4524  case OCLASS_SCHEMA:
4525  {
4526  char *nspname;
4527 
4528  nspname = get_namespace_name_or_temp(object->objectId);
4529  if (!nspname)
4530  elog(ERROR, "cache lookup failed for namespace %u",
4531  object->objectId);
4532  appendStringInfoString(&buffer,
4533  quote_identifier(nspname));
4534  if (objname)
4535  *objname = list_make1(nspname);
4536  break;
4537  }
4538 
4539  case OCLASS_STATISTIC_EXT:
4540  {
4541  HeapTuple tup;
4542  Form_pg_statistic_ext formStatistic;
4543  char *schema;
4544 
4546  ObjectIdGetDatum(object->objectId));
4547  if (!HeapTupleIsValid(tup))
4548  elog(ERROR, "cache lookup failed for statistics object %u",
4549  object->objectId);
4550  formStatistic = (Form_pg_statistic_ext) GETSTRUCT(tup);
4551  schema = get_namespace_name_or_temp(formStatistic->stxnamespace);
4552  appendStringInfoString(&buffer,
4554  NameStr(formStatistic->stxname)));
4555  if (objname)
4556  *objname = list_make2(schema,
4557  pstrdup(NameStr(formStatistic->stxname)));
4558  ReleaseSysCache(tup);
4559  }
4560  break;
4561 
4562  case OCLASS_TSPARSER:
4563  {
4564  HeapTuple tup;
4565  Form_pg_ts_parser formParser;
4566  char *schema;
4567 
4569  ObjectIdGetDatum(object->objectId));
4570  if (!HeapTupleIsValid(tup))
4571  elog(ERROR, "cache lookup failed for text search parser %u",
4572  object->objectId);
4573  formParser = (Form_pg_ts_parser) GETSTRUCT(tup);
4574  schema = get_namespace_name_or_temp(formParser->prsnamespace);
4575  appendStringInfoString(&buffer,
4577  NameStr(formParser->prsname)));
4578  if (objname)
4579  *objname = list_make2(schema,
4580  pstrdup(NameStr(formParser->prsname)));
4581  ReleaseSysCache(tup);
4582  break;
4583  }
4584 
4585  case OCLASS_TSDICT:
4586  {
4587  HeapTuple tup;
4588  Form_pg_ts_dict formDict;
4589  char *schema;
4590 
4591  tup = SearchSysCache1(TSDICTOID,
4592  ObjectIdGetDatum(object->objectId));
4593  if (!HeapTupleIsValid(tup))
4594  elog(ERROR, "cache lookup failed for text search dictionary %u",
4595  object->objectId);
4596  formDict = (Form_pg_ts_dict) GETSTRUCT(tup);
4597  schema = get_namespace_name_or_temp(formDict->dictnamespace);
4598  appendStringInfoString(&buffer,
4600  NameStr(formDict->dictname)));
4601  if (objname)
4602  *objname = list_make2(schema,
4603  pstrdup(NameStr(formDict->dictname)));
4604  ReleaseSysCache(tup);
4605  break;
4606  }
4607 
4608  case OCLASS_TSTEMPLATE:
4609  {
4610  HeapTuple tup;
4611  Form_pg_ts_template formTmpl;
4612  char *schema;
4613 
4615  ObjectIdGetDatum(object->objectId));
4616  if (!HeapTupleIsValid(tup))
4617  elog(ERROR, "cache lookup failed for text search template %u",
4618  object->objectId);
4619  formTmpl = (Form_pg_ts_template) GETSTRUCT(tup);
4620  schema = get_namespace_name_or_temp(formTmpl->tmplnamespace);
4621  appendStringInfoString(&buffer,
4623  NameStr(formTmpl->tmplname)));
4624  if (objname)
4625  *objname = list_make2(schema,
4626  pstrdup(NameStr(formTmpl->tmplname)));
4627  ReleaseSysCache(tup);
4628  break;
4629  }
4630 
4631  case OCLASS_TSCONFIG:
4632  {
4633  HeapTuple tup;
4634  Form_pg_ts_config formCfg;
4635  char *schema;
4636 
4638  ObjectIdGetDatum(object->objectId));
4639  if (!HeapTupleIsValid(tup))
4640  elog(ERROR, "cache lookup failed for text search configuration %u",
4641  object->objectId);
4642  formCfg = (Form_pg_ts_config) GETSTRUCT(tup);
4643  schema = get_namespace_name_or_temp(formCfg->cfgnamespace);
4644  appendStringInfoString(&buffer,
4646  NameStr(formCfg->cfgname)));
4647  if (objname)
4648  *objname = list_make2(schema,
4649  pstrdup(NameStr(formCfg->cfgname)));
4650  ReleaseSysCache(tup);
4651  break;
4652  }
4653 
4654  case OCLASS_ROLE:
4655  {
4656  char *username;
4657 
4658  username = GetUserNameFromId(object->objectId, false);
4659  if (objname)
4660  *objname = list_make1(username);
4661  appendStringInfoString(&buffer,
4662  quote_identifier(username));
4663  break;
4664  }
4665 
4666  case OCLASS_DATABASE:
4667  {
4668  char *datname;
4669 
4670  datname = get_database_name(object->objectId);
4671  if (!datname)
4672  elog(ERROR, "cache lookup failed for database %u",
4673  object->objectId);
4674  if (objname)
4675  *objname = list_make1(datname);
4676  appendStringInfoString(&buffer,
4677  quote_identifier(datname));
4678  break;
4679  }
4680 
4681  case OCLASS_TBLSPACE:
4682  {
4683  char *tblspace;
4684 
4685  tblspace = get_tablespace_name(object->objectId);
4686  if (!tblspace)
4687  elog(ERROR, "cache lookup failed for tablespace %u",
4688  object->objectId);
4689  if (objname)
4690  *objname = list_make1(tblspace);
4691  appendStringInfoString(&buffer,
4692  quote_identifier(tblspace));
4693  break;
4694  }
4695 
4696  case OCLASS_FDW:
4697  {
4698  ForeignDataWrapper *fdw;
4699 
4700  fdw = GetForeignDataWrapper(object->objectId);
4702  if (objname)
4703  *objname = list_make1(pstrdup(fdw->fdwname));
4704  break;
4705  }
4706 
4707  case OCLASS_FOREIGN_SERVER:
4708  {
4709  ForeignServer *srv;
4710 
4711  srv = GetForeignServer(object->objectId);
4712  appendStringInfoString(&buffer,
4714  if (objname)
4715  *objname = list_make1(pstrdup(srv->servername));
4716  break;
4717  }
4718 
4719  case OCLASS_USER_MAPPING:
4720  {
4721  HeapTuple tup;
4722  Oid useid;
4723  Form_pg_user_mapping umform;
4724  ForeignServer *srv;
4725  const char *usename;
4726 
4728  ObjectIdGetDatum(object->objectId));
4729  if (!HeapTupleIsValid(tup))
4730  elog(ERROR, "cache lookup failed for user mapping %u",
4731  object->objectId);
4732  umform = (Form_pg_user_mapping) GETSTRUCT(tup);
4733  useid = umform->umuser;
4734  srv = GetForeignServer(umform->umserver);
4735 
4736  ReleaseSysCache(tup);
4737 
4738  if (OidIsValid(useid))
4739  usename = GetUserNameFromId(useid, false);
4740  else
4741  usename = "public";
4742 
4743  if (objname)
4744  {
4745  *objname = list_make1(pstrdup(usename));
4746  *objargs = list_make1(pstrdup(srv->servername));
4747  }
4748 
4749  appendStringInfo(&buffer, "%s on server %s",
4750  quote_identifier(usename),
4751  srv->servername);
4752  break;
4753  }
4754 
4755  case OCLASS_DEFACL:
4756  {
4757  Relation defaclrel;
4758  ScanKeyData skey[1];
4759  SysScanDesc rcscan;
4760  HeapTuple tup;
4761  Form_pg_default_acl defacl;
4762  char *schema;
4763  char *username;
4764 
4766 
4767  ScanKeyInit(&skey[0],
4769  BTEqualStrategyNumber, F_OIDEQ,
4770  ObjectIdGetDatum(object->objectId));
4771 
4772  rcscan = systable_beginscan(defaclrel, DefaultAclOidIndexId,
4773  true, NULL, 1, skey);
4774 
4775  tup = systable_getnext(rcscan);
4776 
4777  if (!HeapTupleIsValid(tup))
4778  elog(ERROR, "could not find tuple for default ACL %u",
4779  object->objectId);
4780 
4781  defacl = (Form_pg_default_acl) GETSTRUCT(tup);
4782 
4783  username = GetUserNameFromId(defacl->defaclrole, false);
4784  appendStringInfo(&buffer,
4785  "for role %s",
4786  quote_identifier(username));
4787 
4788  if (OidIsValid(defacl->defaclnamespace))
4789  {
4790  schema = get_namespace_name_or_temp(defacl->defaclnamespace);
4791  appendStringInfo(&buffer,
4792  " in schema %s",
4793  quote_identifier(schema));
4794  }
4795  else
4796  schema = NULL;
4797 
4798  switch (defacl->defaclobjtype)
4799  {
4800  case DEFACLOBJ_RELATION:
4801  appendStringInfoString(&buffer,
4802  " on tables");
4803  break;
4804  case DEFACLOBJ_SEQUENCE:
4805  appendStringInfoString(&buffer,
4806  " on sequences");
4807  break;
4808  case DEFACLOBJ_FUNCTION:
4809  appendStringInfoString(&buffer,
4810  " on functions");
4811  break;
4812  case DEFACLOBJ_TYPE:
4813  appendStringInfoString(&buffer,
4814  " on types");
4815  break;
4816  case DEFACLOBJ_NAMESPACE:
4817  appendStringInfoString(&buffer,
4818  " on schemas");
4819  break;
4820  }
4821 
4822  if (objname)
4823  {
4824  *objname = list_make1(username);
4825  if (schema)
4826  *objname = lappend(*objname, schema);
4827  *objargs = list_make1(psprintf("%c", defacl->defaclobjtype));
4828  }
4829 
4830  systable_endscan(rcscan);
4831  heap_close(defaclrel, AccessShareLock);
4832  break;
4833  }
4834 
4835  case OCLASS_EXTENSION:
4836  {
4837  char *extname;
4838 
4839  extname = get_extension_name(object->objectId);
4840  if (!extname)
4841  elog(ERROR, "cache lookup failed for extension %u",
4842  object->objectId);
4843  appendStringInfoString(&buffer, quote_identifier(extname));
4844  if (objname)
4845  *objname = list_make1(extname);
4846  break;
4847  }
4848 
4849  case OCLASS_EVENT_TRIGGER:
4850  {
4851  HeapTuple tup;
4852  Form_pg_event_trigger trigForm;
4853 
4854  /* no objname support here */
4855  if (objname)
4856  *objname = NIL;
4857 
4859  ObjectIdGetDatum(object->objectId));
4860  if (!HeapTupleIsValid(tup))
4861  elog(ERROR, "cache lookup failed for event trigger %u",
4862  object->objectId);
4863  trigForm = (Form_pg_event_trigger) GETSTRUCT(tup);
4864  appendStringInfoString(&buffer,
4865  quote_identifier(NameStr(trigForm->evtname)));
4866  ReleaseSysCache(tup);
4867  break;
4868  }
4869 
4870  case OCLASS_POLICY:
4871  {
4872  Relation polDesc;
4873  HeapTuple tup;
4874  Form_pg_policy policy;
4875 
4877 
4878  tup = get_catalog_object_by_oid(polDesc, object->objectId);
4879 
4880  if (!HeapTupleIsValid(tup))
4881  elog(ERROR, "could not find tuple for policy %u",
4882  object->objectId);
4883 
4884  policy = (Form_pg_policy) GETSTRUCT(tup);
4885 
4886  appendStringInfo(&buffer, "%s on ",
4887  quote_identifier(NameStr(policy->polname)));
4888  getRelationIdentity(&buffer, policy->polrelid, objname);
4889  if (objname)
4890  *objname = lappend(*objname, pstrdup(NameStr(policy->polname)));
4891 
4892  heap_close(polDesc, AccessShareLock);
4893  break;
4894  }
4895 
4896  case OCLASS_PUBLICATION:
4897  {
4898  char *pubname;
4899 
4900  pubname = get_publication_name(object->objectId);
4901  appendStringInfoString(&buffer,
4902  quote_identifier(pubname));
4903  if (objname)
4904  *objname = list_make1(pubname);
4905  break;
4906  }
4907 
4909  {
4910  HeapTuple tup;
4911  char *pubname;
4912  Form_pg_publication_rel prform;
4913 
4915  ObjectIdGetDatum(object->objectId));
4916  if (!HeapTupleIsValid(tup))
4917  elog(ERROR, "cache lookup failed for publication table %u",
4918  object->objectId);
4919 
4920  prform = (Form_pg_publication_rel) GETSTRUCT(tup);
4921  pubname = get_publication_name(prform->prpubid);
4922 
4923  appendStringInfo(&buffer, _("%s in publication %s"),
4924  get_rel_name(prform->prrelid), pubname);
4925 
4926  if (objname)
4927  {
4928  getRelationIdentity(&buffer, prform->prrelid, objname);
4929  *objargs = list_make1(pubname);
4930  }
4931 
4932  ReleaseSysCache(tup);
4933  break;
4934  }
4935 
4936  case OCLASS_SUBSCRIPTION:
4937  {
4938  char *subname;
4939 
4940  subname = get_subscription_name(object->objectId);
4941  appendStringInfoString(&buffer,
4942  quote_identifier(subname));
4943  if (objname)
4944  *objname = list_make1(subname);
4945  break;
4946  }
4947 
4948  case OCLASS_TRANSFORM:
4949  {
4950  Relation transformDesc;
4951  HeapTuple tup;
4952  Form_pg_transform transform;
4953  char *transformLang;
4954  char *transformType;
4955 
4956  transformDesc = heap_open(TransformRelationId, AccessShareLock);
4957 
4958  tup = get_catalog_object_by_oid(transformDesc, object->objectId);
4959 
4960  if (!HeapTupleIsValid(tup))
4961  elog(ERROR, "could not find tuple for transform %u",
4962  object->objectId);
4963 
4964  transform = (Form_pg_transform) GETSTRUCT(tup);
4965 
4966  transformType = format_type_be_qualified(transform->trftype);
4967  transformLang = get_language_name(transform->trflang, false);
4968 
4969  appendStringInfo(&buffer, "for %s on language %s",
4970  transformType,
4971  transformLang);
4972  if (objname)
4973  {
4974  *objname = list_make1(transformType);
4975  *objargs = list_make1(pstrdup(transformLang));
4976  }
4977 
4978  heap_close(transformDesc, AccessShareLock);
4979  }
4980  break;
4981 
4982  /*
4983  * There's intentionally no default: case here; we want the
4984  * compiler to warn if a new OCLASS hasn't been handled above.
4985  */
4986  }
4987 
4988  /*
4989  * If a get_object_address representation was requested, make sure we are
4990  * providing one. We don't check objargs, because many of the cases above
4991  * leave it as NIL.
4992  */
4993  if (objname && *objname == NIL)
4994  elog(ERROR, "requested object address for unsupported object class %d: text result \"%s\"",
4995  (int) getObjectClass(object), buffer.data);
4996 
4997  return buffer.data;
4998 }
4999 
5000 static void
5001 getOpFamilyIdentity(StringInfo buffer, Oid opfid, List **object)
5002 {
5003  HeapTuple opfTup;
5004  Form_pg_opfamily opfForm;
5005  HeapTuple amTup;
5006  Form_pg_am amForm;
5007  char *schema;
5008 
5009  opfTup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfid));
5010  if (!HeapTupleIsValid(opfTup))
5011  elog(ERROR, "cache lookup failed for opfamily %u", opfid);
5012  opfForm = (Form_pg_opfamily) GETSTRUCT(opfTup);
5013 
5014  amTup = SearchSysCache1(AMOID, ObjectIdGetDatum(opfForm->opfmethod));
5015  if (!HeapTupleIsValid(amTup))
5016  elog(ERROR, "cache lookup failed for access method %u",
5017  opfForm->opfmethod);
5018  amForm = (Form_pg_am) GETSTRUCT(amTup);
5019 
5020  schema = get_namespace_name_or_temp(opfForm->opfnamespace);
5021  appendStringInfo(buffer, "%s USING %s",
5023  NameStr(opfForm->opfname)),
5024  NameStr(amForm->amname));
5025 
5026  if (object)
5027  *object = list_make3(pstrdup(NameStr(amForm->amname)),
5028  pstrdup(schema),
5029  pstrdup(NameStr(opfForm->opfname)));
5030 
5031  ReleaseSysCache(amTup);
5032  ReleaseSysCache(opfTup);
5033 }
5034 
5035 /*
5036  * Append the relation identity (quoted qualified name) to the given
5037  * StringInfo.
5038  */
5039 static void
5040 getRelationIdentity(StringInfo buffer, Oid relid, List **object)
5041 {
5042  HeapTuple relTup;
5043  Form_pg_class relForm;
5044  char *schema;
5045 
5046  relTup = SearchSysCache1(RELOID,
5047  ObjectIdGetDatum(relid));
5048  if (!HeapTupleIsValid(relTup))
5049  elog(ERROR, "cache lookup failed for relation %u", relid);
5050  relForm = (Form_pg_class) GETSTRUCT(relTup);
5051 
5052  schema = get_namespace_name_or_temp(relForm->relnamespace);
5053  appendStringInfoString(buffer,
5055  NameStr(relForm->relname)));
5056  if (object)
5057  *object = list_make2(schema, pstrdup(NameStr(relForm->relname)));
5058 
5059  ReleaseSysCache(relTup);
5060 }
5061 
5062 /*
5063  * Auxiliary function to build a TEXT array out of a list of C-strings.
5064  */
5065 ArrayType *
5067 {
5068  ArrayType *arr;
5069  Datum *datums;
5070  int j = 0;
5071  ListCell *cell;
5072  MemoryContext memcxt;
5073  MemoryContext oldcxt;
5074 
5075  /* Work in a temp context; easier than individually pfree'ing the Datums */
5077  "strlist to array",
5079  oldcxt = MemoryContextSwitchTo(memcxt);
5080 
5081  datums = (Datum *) palloc(sizeof(Datum) * list_length(list));
5082 
5083  foreach(cell, list)
5084  {
5085  char *name = lfirst(cell);
5086 
5087  datums[j++] = CStringGetTextDatum(name);
5088  }
5089 
5090  MemoryContextSwitchTo(oldcxt);
5091 
5092  arr = construct_array(datums, list_length(list),
5093  TEXTOID, -1, false, 'i');
5094 
5095  MemoryContextDelete(memcxt);
5096 
5097  return arr;
5098 }
#define list_make2(x1, x2)
Definition: pg_list.h:140
bool has_createrole_privilege(Oid roleid)
Definition: aclchk.c:5229
bool pg_collation_ownercheck(Oid coll_oid, Oid roleid)
Definition: aclchk.c:5048
Value * makeString(char *str)
Definition: value.c:53
Type LookupTypeName(ParseState *pstate, const TypeName *typeName, int32 *typmod_p, bool missing_ok)
Definition: parse_type.c:57
#define Anum_pg_database_datdba
Definition: pg_database.h:65
#define list_make3(x1, x2, x3)
Definition: pg_list.h:141
Oid LookupOperWithArgs(ObjectWithArgs *oper, bool noError)
Definition: parse_oper.c:140
#define ConstraintOidIndexId
Definition: indexing.h:130
#define Anum_pg_event_trigger_evtname
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:611
bool get_object_namensp_unique(Oid class_id)
#define NIL
Definition: pg_list.h:69
#define Anum_pg_tablespace_spcacl
Definition: pg_tablespace.h:57
#define NamespaceOidIndexId
Definition: indexing.h:195
Oid get_tablespace_oid(const char *tablespacename, bool missing_ok)
Definition: tablespace.c:1380
#define TYPTYPE_DOMAIN
Definition: pg_type.h:722
#define ProcedureOidIndexId
Definition: indexing.h:216
Relation relation_openrv(const RangeVar *relation, LOCKMODE lockmode)
Definition: heapam.c:1198
#define PG_GETARG_INT32(n)
Definition: fmgr.h:234
#define NamespaceRelationId
Definition: pg_namespace.h:34
#define CollationOidIndexId
Definition: indexing.h:121
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:198
#define Anum_pg_operator_oprowner
Definition: pg_operator.h:67
Oid get_namespace_oid(const char *nspname, bool missing_ok)
Definition: namespace.c:3005
#define RewriteOidIndexId
Definition: indexing.h:221
#define TriggerOidIndexId
Definition: indexing.h:251
#define OperatorRelationId
Definition: pg_operator.h:32
int errhint(const char *fmt,...)
Definition: elog.c:987
static void getConstraintTypeDescription(StringInfo buffer, Oid constroid)
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:499
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
static ObjectAddress get_object_address_usermapping(List *object, bool missing_ok)
#define Anum_pg_foreign_data_wrapper_fdwowner
bool lo_compat_privileges
Definition: inv_api.c:57
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:4737
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:10412
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:4887
FormData_pg_ts_config * Form_pg_ts_config
Definition: pg_ts_config.h:41
#define RelationGetDescr(relation)
Definition: rel.h:437
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:4708
#define castNode(_type_, nodeptr)
Definition: nodes.h:581
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:4914
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 DatumGetObjectId(X)
Definition: postgres.h:506
char * pstrdup(const char *in)
Definition: mcxt.c:1063
#define DatabaseRelationId
Definition: pg_database.h:29
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
#define RelationRelationId
Definition: pg_class.h:29
#define Anum_pg_language_lanacl
Definition: pg_language.h:65
char * get_extension_name(Oid ext_oid)
Definition: extension.c:180
#define Anum_pg_opfamily_opfowner
Definition: pg_opfamily.h:54
static void getOpFamilyIdentity(StringInfo buffer, Oid opfid, List **object)
char * getObjectIdentityParts(const ObjectAddress *object, List **objname, List **objargs)
int get_object_catcache_name(Oid class_id)
bool pg_foreign_server_ownercheck(Oid srv_oid, Oid roleid)
Definition: aclchk.c:4968
#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:3279
#define AccessShareLock
Definition: lockdefs.h:36
#define OperatorClassRelationId
Definition: pg_opclass.h:49
#define INT4OID
Definition: pg_type.h:316
#define Anum_pg_proc_proacl
Definition: pg_proc.h:118
bool pg_publication_ownercheck(Oid pub_oid, Oid roleid)
Definition: aclchk.c:5142
#define Anum_pg_opclass_opcowner
Definition: pg_opclass.h:78
Oid get_object_oid_index(Oid class_id)
List * list_copy(const List *oldlist)
Definition: list.c:1160
static void getOpFamilyDescription(StringInfo buffer, Oid opfid)
Definition: nodes.h:512
#define AttrDefaultOidIndexId
Definition: indexing.h:89
#define OperatorFamilyRelationId
Definition: pg_opfamily.h:29
#define strVal(v)
Definition: value.h:54
#define AccessMethodOperatorOidIndexId
Definition: indexing.h:79
bool pg_oper_ownercheck(Oid oper_oid, Oid roleid)
Definition: aclchk.c:4656
int errcode(int sqlerrcode)
Definition: elog.c:575
Oid get_ts_config_oid(List *names, bool missing_ok)
Definition: namespace.c:2639