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-2018, 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  ObjectType objtype; /* OBJECT_* 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  OBJECT_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,
341  OBJECT_TABLE,
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,
455  OBJECT_TYPE,
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  relation->rd_rel->relkind != RELKIND_PARTITIONED_INDEX)
1222  ereport(ERROR,
1223  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1224  errmsg("\"%s\" is not an index",
1225  RelationGetRelationName(relation))));
1226  break;
1227  case OBJECT_SEQUENCE:
1228  if (relation->rd_rel->relkind != RELKIND_SEQUENCE)
1229  ereport(ERROR,
1230  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1231  errmsg("\"%s\" is not a sequence",
1232  RelationGetRelationName(relation))));
1233  break;
1234  case OBJECT_TABLE:
1235  if (relation->rd_rel->relkind != RELKIND_RELATION &&
1236  relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
1237  ereport(ERROR,
1238  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1239  errmsg("\"%s\" is not a table",
1240  RelationGetRelationName(relation))));
1241  break;
1242  case OBJECT_VIEW:
1243  if (relation->rd_rel->relkind != RELKIND_VIEW)
1244  ereport(ERROR,
1245  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1246  errmsg("\"%s\" is not a view",
1247  RelationGetRelationName(relation))));
1248  break;
1249  case OBJECT_MATVIEW:
1250  if (relation->rd_rel->relkind != RELKIND_MATVIEW)
1251  ereport(ERROR,
1252  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1253  errmsg("\"%s\" is not a materialized view",
1254  RelationGetRelationName(relation))));
1255  break;
1256  case OBJECT_FOREIGN_TABLE:
1257  if (relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE)
1258  ereport(ERROR,
1259  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1260  errmsg("\"%s\" is not a foreign table",
1261  RelationGetRelationName(relation))));
1262  break;
1263  default:
1264  elog(ERROR, "unrecognized objtype: %d", (int) objtype);
1265  break;
1266  }
1267 
1268  /* Done. */
1269  address.objectId = RelationGetRelid(relation);
1270  *relp = relation;
1271 
1272  return address;
1273 }
1274 
1275 /*
1276  * Find object address for an object that is attached to a relation.
1277  *
1278  * Note that we take only an AccessShareLock on the relation. We need not
1279  * pass down the LOCKMODE from get_object_address(), because that is the lock
1280  * mode for the object itself, not the relation to which it is attached.
1281  */
1282 static ObjectAddress
1284  Relation *relp, bool missing_ok)
1285 {
1286  ObjectAddress address;
1287  Relation relation = NULL;
1288  int nnames;
1289  const char *depname;
1290  List *relname;
1291  Oid reloid;
1292 
1293  /* Extract name of dependent object. */
1294  depname = strVal(llast(object));
1295 
1296  /* Separate relation name from dependent object name. */
1297  nnames = list_length(object);
1298  if (nnames < 2)
1299  ereport(ERROR,
1300  (errcode(ERRCODE_SYNTAX_ERROR),
1301  errmsg("must specify relation and object name")));
1302 
1303  /* Extract relation name and open relation. */
1304  relname = list_truncate(list_copy(object), nnames - 1);
1305  relation = heap_openrv_extended(makeRangeVarFromNameList(relname),
1307  missing_ok);
1308 
1309  reloid = relation ? RelationGetRelid(relation) : InvalidOid;
1310 
1311  switch (objtype)
1312  {
1313  case OBJECT_RULE:
1314  address.classId = RewriteRelationId;
1315  address.objectId = relation ?
1316  get_rewrite_oid(reloid, depname, missing_ok) : InvalidOid;
1317  address.objectSubId = 0;
1318  break;
1319  case OBJECT_TRIGGER:
1320  address.classId = TriggerRelationId;
1321  address.objectId = relation ?
1322  get_trigger_oid(reloid, depname, missing_ok) : InvalidOid;
1323  address.objectSubId = 0;
1324  break;
1325  case OBJECT_TABCONSTRAINT:
1326  address.classId = ConstraintRelationId;
1327  address.objectId = relation ?
1328  get_relation_constraint_oid(reloid, depname, missing_ok) :
1329  InvalidOid;
1330  address.objectSubId = 0;
1331  break;
1332  case OBJECT_POLICY:
1333  address.classId = PolicyRelationId;
1334  address.objectId = relation ?
1335  get_relation_policy_oid(reloid, depname, missing_ok) :
1336  InvalidOid;
1337  address.objectSubId = 0;
1338  break;
1339  default:
1340  elog(ERROR, "unrecognized objtype: %d", (int) objtype);
1341  }
1342 
1343  /* Avoid relcache leak when object not found. */
1344  if (!OidIsValid(address.objectId))
1345  {
1346  if (relation != NULL)
1347  heap_close(relation, AccessShareLock);
1348 
1349  relation = NULL; /* department of accident prevention */
1350  return address;
1351  }
1352 
1353  /* Done. */
1354  *relp = relation;
1355  return address;
1356 }
1357 
1358 /*
1359  * Find the ObjectAddress for an attribute.
1360  */
1361 static ObjectAddress
1363  Relation *relp, LOCKMODE lockmode,
1364  bool missing_ok)
1365 {
1366  ObjectAddress address;
1367  List *relname;
1368  Oid reloid;
1369  Relation relation;
1370  const char *attname;
1371  AttrNumber attnum;
1372 
1373  /* Extract relation name and open relation. */
1374  if (list_length(object) < 2)
1375  ereport(ERROR,
1376  (errcode(ERRCODE_SYNTAX_ERROR),
1377  errmsg("column name must be qualified")));
1378  attname = strVal(lfirst(list_tail(object)));
1379  relname = list_truncate(list_copy(object), list_length(object) - 1);
1380  /* XXX no missing_ok support here */
1381  relation = relation_openrv(makeRangeVarFromNameList(relname), lockmode);
1382  reloid = RelationGetRelid(relation);
1383 
1384  /* Look up attribute and construct return value. */
1385  attnum = get_attnum(reloid, attname);
1386  if (attnum == InvalidAttrNumber)
1387  {
1388  if (!missing_ok)
1389  ereport(ERROR,
1390  (errcode(ERRCODE_UNDEFINED_COLUMN),
1391  errmsg("column \"%s\" of relation \"%s\" does not exist",
1392  attname, NameListToString(relname))));
1393 
1394  address.classId = RelationRelationId;
1395  address.objectId = InvalidOid;
1396  address.objectSubId = InvalidAttrNumber;
1397  relation_close(relation, lockmode);
1398  return address;
1399  }
1400 
1401  address.classId = RelationRelationId;
1402  address.objectId = reloid;
1403  address.objectSubId = attnum;
1404 
1405  *relp = relation;
1406  return address;
1407 }
1408 
1409 /*
1410  * Find the ObjectAddress for an attribute's default value.
1411  */
1412 static ObjectAddress
1414  Relation *relp, LOCKMODE lockmode,
1415  bool missing_ok)
1416 {
1417  ObjectAddress address;
1418  List *relname;
1419  Oid reloid;
1420  Relation relation;
1421  const char *attname;
1422  AttrNumber attnum;
1423  TupleDesc tupdesc;
1424  Oid defoid;
1425 
1426  /* Extract relation name and open relation. */
1427  if (list_length(object) < 2)
1428  ereport(ERROR,
1429  (errcode(ERRCODE_SYNTAX_ERROR),
1430  errmsg("column name must be qualified")));
1431  attname = strVal(llast(object));
1432  relname = list_truncate(list_copy(object), list_length(object) - 1);
1433  /* XXX no missing_ok support here */
1434  relation = relation_openrv(makeRangeVarFromNameList(relname), lockmode);
1435  reloid = RelationGetRelid(relation);
1436 
1437  tupdesc = RelationGetDescr(relation);
1438 
1439  /* Look up attribute number and scan pg_attrdef to find its tuple */
1440  attnum = get_attnum(reloid, attname);
1441  defoid = InvalidOid;
1442  if (attnum != InvalidAttrNumber && tupdesc->constr != NULL)
1443  {
1444  Relation attrdef;
1445  ScanKeyData keys[2];
1446  SysScanDesc scan;
1447  HeapTuple tup;
1448 
1450  ScanKeyInit(&keys[0],
1453  F_OIDEQ,
1454  ObjectIdGetDatum(reloid));
1455  ScanKeyInit(&keys[1],
1458  F_INT2EQ,
1459  Int16GetDatum(attnum));
1460  scan = systable_beginscan(attrdef, AttrDefaultIndexId, true,
1461  NULL, 2, keys);
1462  if (HeapTupleIsValid(tup = systable_getnext(scan)))
1463  defoid = HeapTupleGetOid(tup);
1464 
1465  systable_endscan(scan);
1466  relation_close(attrdef, AccessShareLock);
1467  }
1468  if (!OidIsValid(defoid))
1469  {
1470  if (!missing_ok)
1471  ereport(ERROR,
1472  (errcode(ERRCODE_UNDEFINED_COLUMN),
1473  errmsg("default value for column \"%s\" of relation \"%s\" does not exist",
1474  attname, NameListToString(relname))));
1475 
1476  address.classId = AttrDefaultRelationId;
1477  address.objectId = InvalidOid;
1478  address.objectSubId = InvalidAttrNumber;
1479  relation_close(relation, lockmode);
1480  return address;
1481  }
1482 
1483  address.classId = AttrDefaultRelationId;
1484  address.objectId = defoid;
1485  address.objectSubId = 0;
1486 
1487  *relp = relation;
1488  return address;
1489 }
1490 
1491 /*
1492  * Find the ObjectAddress for a type or domain
1493  */
1494 static ObjectAddress
1495 get_object_address_type(ObjectType objtype, TypeName *typename, bool missing_ok)
1496 {
1497  ObjectAddress address;
1498  Type tup;
1499 
1500  address.classId = TypeRelationId;
1501  address.objectId = InvalidOid;
1502  address.objectSubId = 0;
1503 
1504  tup = LookupTypeName(NULL, typename, NULL, missing_ok);
1505  if (!HeapTupleIsValid(tup))
1506  {
1507  if (!missing_ok)
1508  ereport(ERROR,
1509  (errcode(ERRCODE_UNDEFINED_OBJECT),
1510  errmsg("type \"%s\" does not exist",
1511  TypeNameToString(typename))));
1512  return address;
1513  }
1514  address.objectId = typeTypeId(tup);
1515 
1516  if (objtype == OBJECT_DOMAIN)
1517  {
1518  if (((Form_pg_type) GETSTRUCT(tup))->typtype != TYPTYPE_DOMAIN)
1519  ereport(ERROR,
1520  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1521  errmsg("\"%s\" is not a domain",
1522  TypeNameToString(typename))));
1523  }
1524 
1525  ReleaseSysCache(tup);
1526 
1527  return address;
1528 }
1529 
1530 /*
1531  * Find the ObjectAddress for an opclass or opfamily.
1532  */
1533 static ObjectAddress
1534 get_object_address_opcf(ObjectType objtype, List *object, bool missing_ok)
1535 {
1536  Oid amoid;
1537  ObjectAddress address;
1538 
1539  /* XXX no missing_ok support here */
1540  amoid = get_index_am_oid(strVal(linitial(object)), false);
1541  object = list_copy_tail(object, 1);
1542 
1543  switch (objtype)
1544  {
1545  case OBJECT_OPCLASS:
1546  address.classId = OperatorClassRelationId;
1547  address.objectId = get_opclass_oid(amoid, object, missing_ok);
1548  address.objectSubId = 0;
1549  break;
1550  case OBJECT_OPFAMILY:
1552  address.objectId = get_opfamily_oid(amoid, object, missing_ok);
1553  address.objectSubId = 0;
1554  break;
1555  default:
1556  elog(ERROR, "unrecognized objtype: %d", (int) objtype);
1557  /* placate compiler, which doesn't know elog won't return */
1558  address.classId = InvalidOid;
1559  address.objectId = InvalidOid;
1560  address.objectSubId = 0;
1561  }
1562 
1563  return address;
1564 }
1565 
1566 /*
1567  * Find the ObjectAddress for an opclass/opfamily member.
1568  *
1569  * (The returned address corresponds to a pg_amop/pg_amproc object).
1570  */
1571 static ObjectAddress
1573  List *object, bool missing_ok)
1574 {
1575  ObjectAddress famaddr;
1576  ObjectAddress address;
1577  ListCell *cell;
1578  List *copy;
1579  TypeName *typenames[2];
1580  Oid typeoids[2];
1581  int membernum;
1582  int i;
1583 
1584  /*
1585  * The last element of the object list contains the strategy or procedure
1586  * number. We need to strip that out before getting the opclass/family
1587  * address. The rest can be used directly by get_object_address_opcf().
1588  */
1589  membernum = atoi(strVal(llast(linitial(object))));
1590  copy = list_truncate(list_copy(linitial(object)), list_length(linitial(object)) - 1);
1591 
1592  /* no missing_ok support here */
1593  famaddr = get_object_address_opcf(OBJECT_OPFAMILY, copy, false);
1594 
1595  /* find out left/right type names and OIDs */
1596  typenames[0] = typenames[1] = NULL;
1597  typeoids[0] = typeoids[1] = InvalidOid;
1598  i = 0;
1599  foreach(cell, lsecond(object))
1600  {
1601  ObjectAddress typaddr;
1602 
1603  typenames[i] = lfirst_node(TypeName, cell);
1604  typaddr = get_object_address_type(OBJECT_TYPE, typenames[i], missing_ok);
1605  typeoids[i] = typaddr.objectId;
1606  if (++i >= 2)
1607  break;
1608  }
1609 
1610  switch (objtype)
1611  {
1612  case OBJECT_AMOP:
1613  {
1614  HeapTuple tp;
1615 
1617  InvalidOid);
1618 
1620  ObjectIdGetDatum(famaddr.objectId),
1621  ObjectIdGetDatum(typeoids[0]),
1622  ObjectIdGetDatum(typeoids[1]),
1623  Int16GetDatum(membernum));
1624  if (!HeapTupleIsValid(tp))
1625  {
1626  if (!missing_ok)
1627  ereport(ERROR,
1628  (errcode(ERRCODE_UNDEFINED_OBJECT),
1629  errmsg("operator %d (%s, %s) of %s does not exist",
1630  membernum,
1631  TypeNameToString(typenames[0]),
1632  TypeNameToString(typenames[1]),
1633  getObjectDescription(&famaddr))));
1634  }
1635  else
1636  {
1637  address.objectId = HeapTupleGetOid(tp);
1638  ReleaseSysCache(tp);
1639  }
1640  }
1641  break;
1642 
1643  case OBJECT_AMPROC:
1644  {
1645  HeapTuple tp;
1646 
1648  InvalidOid);
1649 
1651  ObjectIdGetDatum(famaddr.objectId),
1652  ObjectIdGetDatum(typeoids[0]),
1653  ObjectIdGetDatum(typeoids[1]),
1654  Int16GetDatum(membernum));
1655  if (!HeapTupleIsValid(tp))
1656  {
1657  if (!missing_ok)
1658  ereport(ERROR,
1659  (errcode(ERRCODE_UNDEFINED_OBJECT),
1660  errmsg("function %d (%s, %s) of %s does not exist",
1661  membernum,
1662  TypeNameToString(typenames[0]),
1663  TypeNameToString(typenames[1]),
1664  getObjectDescription(&famaddr))));
1665  }
1666  else
1667  {
1668  address.objectId = HeapTupleGetOid(tp);
1669  ReleaseSysCache(tp);
1670  }
1671  }
1672  break;
1673  default:
1674  elog(ERROR, "unrecognized objtype: %d", (int) objtype);
1675  }
1676 
1677  return address;
1678 }
1679 
1680 /*
1681  * Find the ObjectAddress for a user mapping.
1682  */
1683 static ObjectAddress
1684 get_object_address_usermapping(List *object, bool missing_ok)
1685 {
1686  ObjectAddress address;
1687  Oid userid;
1688  char *username;
1689  char *servername;
1690  ForeignServer *server;
1691  HeapTuple tp;
1692 
1694 
1695  /* fetch string names from input lists, for error messages */
1696  username = strVal(linitial(object));
1697  servername = strVal(lsecond(object));
1698 
1699  /* look up pg_authid OID of mapped user; InvalidOid if PUBLIC */
1700  if (strcmp(username, "public") == 0)
1701  userid = InvalidOid;
1702  else
1703  {
1705  CStringGetDatum(username));
1706  if (!HeapTupleIsValid(tp))
1707  {
1708  if (!missing_ok)
1709  ereport(ERROR,
1710  (errcode(ERRCODE_UNDEFINED_OBJECT),
1711  errmsg("user mapping for user \"%s\" on server \"%s\" does not exist",
1712  username, servername)));
1713  return address;
1714  }
1715  userid = HeapTupleGetOid(tp);
1716  ReleaseSysCache(tp);
1717  }
1718 
1719  /* Now look up the pg_user_mapping tuple */
1720  server = GetForeignServerByName(servername, true);
1721  if (!server)
1722  {
1723  if (!missing_ok)
1724  ereport(ERROR,
1725  (errcode(ERRCODE_UNDEFINED_OBJECT),
1726  errmsg("server \"%s\" does not exist", servername)));
1727  return address;
1728  }
1729  tp = SearchSysCache2(USERMAPPINGUSERSERVER,
1730  ObjectIdGetDatum(userid),
1731  ObjectIdGetDatum(server->serverid));
1732  if (!HeapTupleIsValid(tp))
1733  {
1734  if (!missing_ok)
1735  ereport(ERROR,
1736  (errcode(ERRCODE_UNDEFINED_OBJECT),
1737  errmsg("user mapping for user \"%s\" on server \"%s\" does not exist",
1738  username, servername)));
1739  return address;
1740  }
1741 
1742  address.objectId = HeapTupleGetOid(tp);
1743 
1744  ReleaseSysCache(tp);
1745 
1746  return address;
1747 }
1748 
1749 /*
1750  * Find the ObjectAddress for a publication relation. The first element of
1751  * the object parameter is the relation name, the second is the
1752  * publication name.
1753  */
1754 static ObjectAddress
1756  Relation *relp, bool missing_ok)
1757 {
1758  ObjectAddress address;
1759  Relation relation;
1760  List *relname;
1761  char *pubname;
1762  Publication *pub;
1763 
1765 
1766  relname = linitial(object);
1768  AccessShareLock, missing_ok);
1769  if (!relation)
1770  return address;
1771 
1772  /* fetch publication name from input list */
1773  pubname = strVal(lsecond(object));
1774 
1775  /* Now look up the pg_publication tuple */
1776  pub = GetPublicationByName(pubname, missing_ok);
1777  if (!pub)
1778  {
1779  relation_close(relation, AccessShareLock);
1780  return address;
1781  }
1782 
1783  /* Find the publication relation mapping in syscache. */
1784  address.objectId =
1787  ObjectIdGetDatum(pub->oid));
1788  if (!OidIsValid(address.objectId))
1789  {
1790  if (!missing_ok)
1791  ereport(ERROR,
1792  (errcode(ERRCODE_UNDEFINED_OBJECT),
1793  errmsg("publication relation \"%s\" in publication \"%s\" does not exist",
1794  RelationGetRelationName(relation), pubname)));
1795  relation_close(relation, AccessShareLock);
1796  return address;
1797  }
1798 
1799  *relp = relation;
1800  return address;
1801 }
1802 
1803 /*
1804  * Find the ObjectAddress for a default ACL.
1805  */
1806 static ObjectAddress
1807 get_object_address_defacl(List *object, bool missing_ok)
1808 {
1809  HeapTuple tp;
1810  Oid userid;
1811  Oid schemaid;
1812  char *username;
1813  char *schema;
1814  char objtype;
1815  char *objtype_str;
1816  ObjectAddress address;
1817 
1819 
1820  /*
1821  * First figure out the textual attributes so that they can be used for
1822  * error reporting.
1823  */
1824  username = strVal(lsecond(object));
1825  if (list_length(object) >= 3)
1826  schema = (char *) strVal(lthird(object));
1827  else
1828  schema = NULL;
1829 
1830  /*
1831  * Decode defaclobjtype. Only first char is considered; the rest of the
1832  * string, if any, is blissfully ignored.
1833  */
1834  objtype = ((char *) strVal(linitial(object)))[0];
1835  switch (objtype)
1836  {
1837  case DEFACLOBJ_RELATION:
1838  objtype_str = "tables";
1839  break;
1840  case DEFACLOBJ_SEQUENCE:
1841  objtype_str = "sequences";
1842  break;
1843  case DEFACLOBJ_FUNCTION:
1844  objtype_str = "functions";
1845  break;
1846  case DEFACLOBJ_TYPE:
1847  objtype_str = "types";
1848  break;
1849  case DEFACLOBJ_NAMESPACE:
1850  objtype_str = "schemas";
1851  break;
1852  default:
1853  ereport(ERROR,
1854  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1855  errmsg("unrecognized default ACL object type \"%c\"", objtype),
1856  errhint("Valid object types are \"%c\", \"%c\", \"%c\", \"%c\", \"%c\".",
1862  }
1863 
1864  /*
1865  * Look up user ID. Behave as "default ACL not found" if the user doesn't
1866  * exist.
1867  */
1869  CStringGetDatum(username));
1870  if (!HeapTupleIsValid(tp))
1871  goto not_found;
1872  userid = HeapTupleGetOid(tp);
1873  ReleaseSysCache(tp);
1874 
1875  /*
1876  * If a schema name was given, look up its OID. If it doesn't exist,
1877  * behave as "default ACL not found".
1878  */
1879  if (schema)
1880  {
1881  schemaid = get_namespace_oid(schema, true);
1882  if (schemaid == InvalidOid)
1883  goto not_found;
1884  }
1885  else
1886  schemaid = InvalidOid;
1887 
1888  /* Finally, look up the pg_default_acl object */
1890  ObjectIdGetDatum(userid),
1891  ObjectIdGetDatum(schemaid),
1892  CharGetDatum(objtype));
1893  if (!HeapTupleIsValid(tp))
1894  goto not_found;
1895 
1896  address.objectId = HeapTupleGetOid(tp);
1897  ReleaseSysCache(tp);
1898 
1899  return address;
1900 
1901 not_found:
1902  if (!missing_ok)
1903  {
1904  if (schema)
1905  ereport(ERROR,
1906  (errcode(ERRCODE_UNDEFINED_OBJECT),
1907  errmsg("default ACL for user \"%s\" in schema \"%s\" on %s does not exist",
1908  username, schema, objtype_str)));
1909  else
1910  ereport(ERROR,
1911  (errcode(ERRCODE_UNDEFINED_OBJECT),
1912  errmsg("default ACL for user \"%s\" on %s does not exist",
1913  username, objtype_str)));
1914  }
1915  return address;
1916 }
1917 
1918 /*
1919  * Convert an array of TEXT into a List of string Values, as emitted by the
1920  * parser, which is what get_object_address uses as input.
1921  */
1922 static List *
1924 {
1925  Datum *elems;
1926  bool *nulls;
1927  int nelems;
1928  List *list = NIL;
1929  int i;
1930 
1931  deconstruct_array(arr, TEXTOID, -1, false, 'i',
1932  &elems, &nulls, &nelems);
1933 
1934  for (i = 0; i < nelems; i++)
1935  {
1936  if (nulls[i])
1937  ereport(ERROR,
1938  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1939  errmsg("name or argument lists may not contain nulls")));
1940  list = lappend(list, makeString(TextDatumGetCString(elems[i])));
1941  }
1942 
1943  return list;
1944 }
1945 
1946 /*
1947  * SQL-callable version of get_object_address
1948  */
1949 Datum
1951 {
1952  char *ttype = TextDatumGetCString(PG_GETARG_DATUM(0));
1953  ArrayType *namearr = PG_GETARG_ARRAYTYPE_P(1);
1954  ArrayType *argsarr = PG_GETARG_ARRAYTYPE_P(2);
1955  int itype;
1956  ObjectType type;
1957  List *name = NIL;
1958  TypeName *typename = NULL;
1959  List *args = NIL;
1960  Node *objnode = NULL;
1961  ObjectAddress addr;
1962  TupleDesc tupdesc;
1963  Datum values[3];
1964  bool nulls[3];
1965  HeapTuple htup;
1966  Relation relation;
1967 
1968  /* Decode object type, raise error if unknown */
1969  itype = read_objtype_from_string(ttype);
1970  if (itype < 0)
1971  ereport(ERROR,
1972  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1973  errmsg("unsupported object type \"%s\"", ttype)));
1974  type = (ObjectType) itype;
1975 
1976  /*
1977  * Convert the text array to the representation appropriate for the given
1978  * object type. Most use a simple string Values list, but there are some
1979  * exceptions.
1980  */
1981  if (type == OBJECT_TYPE || type == OBJECT_DOMAIN || type == OBJECT_CAST ||
1982  type == OBJECT_TRANSFORM || type == OBJECT_DOMCONSTRAINT)
1983  {
1984  Datum *elems;
1985  bool *nulls;
1986  int nelems;
1987 
1988  deconstruct_array(namearr, TEXTOID, -1, false, 'i',
1989  &elems, &nulls, &nelems);
1990  if (nelems != 1)
1991  ereport(ERROR,
1992  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1993  errmsg("name list length must be exactly %d", 1)));
1994  if (nulls[0])
1995  ereport(ERROR,
1996  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1997  errmsg("name or argument lists may not contain nulls")));
1998  typename = typeStringToTypeName(TextDatumGetCString(elems[0]));
1999  }
2000  else if (type == OBJECT_LARGEOBJECT)
2001  {
2002  Datum *elems;
2003  bool *nulls;
2004  int nelems;
2005 
2006  deconstruct_array(namearr, TEXTOID, -1, false, 'i',
2007  &elems, &nulls, &nelems);
2008  if (nelems != 1)
2009  ereport(ERROR,
2010  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2011  errmsg("name list length must be exactly %d", 1)));
2012  if (nulls[0])
2013  ereport(ERROR,
2014  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2015  errmsg("large object OID may not be null")));
2016  objnode = (Node *) makeFloat(TextDatumGetCString(elems[0]));
2017  }
2018  else
2019  {
2020  name = textarray_to_strvaluelist(namearr);
2021  if (list_length(name) < 1)
2022  ereport(ERROR,
2023  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2024  errmsg("name list length must be at least %d", 1)));
2025  }
2026 
2027  /*
2028  * If args are given, decode them according to the object type.
2029  */
2030  if (type == OBJECT_AGGREGATE ||
2031  type == OBJECT_FUNCTION ||
2032  type == OBJECT_PROCEDURE ||
2033  type == OBJECT_ROUTINE ||
2034  type == OBJECT_OPERATOR ||
2035  type == OBJECT_CAST ||
2036  type == OBJECT_AMOP ||
2037  type == OBJECT_AMPROC)
2038  {
2039  /* in these cases, the args list must be of TypeName */
2040  Datum *elems;
2041  bool *nulls;
2042  int nelems;
2043  int i;
2044 
2045  deconstruct_array(argsarr, TEXTOID, -1, false, 'i',
2046  &elems, &nulls, &nelems);
2047 
2048  args = NIL;
2049  for (i = 0; i < nelems; i++)
2050  {
2051  if (nulls[i])
2052  ereport(ERROR,
2053  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2054  errmsg("name or argument lists may not contain nulls")));
2055  args = lappend(args,
2057  }
2058  }
2059  else
2060  {
2061  /* For all other object types, use string Values */
2062  args = textarray_to_strvaluelist(argsarr);
2063  }
2064 
2065  /*
2066  * get_object_address is pretty sensitive to the length its input lists;
2067  * check that they're what it wants.
2068  */
2069  switch (type)
2070  {
2071  case OBJECT_DOMCONSTRAINT:
2072  case OBJECT_CAST:
2073  case OBJECT_USER_MAPPING:
2075  case OBJECT_DEFACL:
2076  case OBJECT_TRANSFORM:
2077  if (list_length(args) != 1)
2078  ereport(ERROR,
2079  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2080  errmsg("argument list length must be exactly %d", 1)));
2081  break;
2082  case OBJECT_OPFAMILY:
2083  case OBJECT_OPCLASS:
2084  if (list_length(name) < 2)
2085  ereport(ERROR,
2086  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2087  errmsg("name list length must be at least %d", 2)));
2088  break;
2089  case OBJECT_AMOP:
2090  case OBJECT_AMPROC:
2091  if (list_length(name) < 3)
2092  ereport(ERROR,
2093  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2094  errmsg("name list length must be at least %d", 3)));
2095  /* fall through to check args length */
2096  case OBJECT_OPERATOR:
2097  if (list_length(args) != 2)
2098  ereport(ERROR,
2099  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2100  errmsg("argument list length must be exactly %d", 2)));
2101  break;
2102  default:
2103  break;
2104  }
2105 
2106  /*
2107  * Now build the Node type that get_object_address() expects for the given
2108  * type.
2109  */
2110  switch (type)
2111  {
2112  case OBJECT_TABLE:
2113  case OBJECT_SEQUENCE:
2114  case OBJECT_VIEW:
2115  case OBJECT_MATVIEW:
2116  case OBJECT_INDEX:
2117  case OBJECT_FOREIGN_TABLE:
2118  case OBJECT_COLUMN:
2119  case OBJECT_ATTRIBUTE:
2120  case OBJECT_COLLATION:
2121  case OBJECT_CONVERSION:
2122  case OBJECT_STATISTIC_EXT:
2123  case OBJECT_TSPARSER:
2124  case OBJECT_TSDICTIONARY:
2125  case OBJECT_TSTEMPLATE:
2127  case OBJECT_DEFAULT:
2128  case OBJECT_POLICY:
2129  case OBJECT_RULE:
2130  case OBJECT_TRIGGER:
2131  case OBJECT_TABCONSTRAINT:
2132  case OBJECT_OPCLASS:
2133  case OBJECT_OPFAMILY:
2134  objnode = (Node *) name;
2135  break;
2136  case OBJECT_ACCESS_METHOD:
2137  case OBJECT_DATABASE:
2138  case OBJECT_EVENT_TRIGGER:
2139  case OBJECT_EXTENSION:
2140  case OBJECT_FDW:
2141  case OBJECT_FOREIGN_SERVER:
2142  case OBJECT_LANGUAGE:
2143  case OBJECT_PUBLICATION:
2144  case OBJECT_ROLE:
2145  case OBJECT_SCHEMA:
2146  case OBJECT_SUBSCRIPTION:
2147  case OBJECT_TABLESPACE:
2148  if (list_length(name) != 1)
2149  ereport(ERROR,
2150  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2151  errmsg("name list length must be exactly %d", 1)));
2152  objnode = linitial(name);
2153  break;
2154  case OBJECT_TYPE:
2155  case OBJECT_DOMAIN:
2156  objnode = (Node *) typename;
2157  break;
2158  case OBJECT_CAST:
2159  case OBJECT_DOMCONSTRAINT:
2160  case OBJECT_TRANSFORM:
2161  objnode = (Node *) list_make2(typename, linitial(args));
2162  break;
2164  objnode = (Node *) list_make2(name, linitial(args));
2165  break;
2166  case OBJECT_USER_MAPPING:
2167  objnode = (Node *) list_make2(linitial(name), linitial(args));
2168  break;
2169  case OBJECT_DEFACL:
2170  objnode = (Node *) lcons(linitial(args), name);
2171  break;
2172  case OBJECT_AMOP:
2173  case OBJECT_AMPROC:
2174  objnode = (Node *) list_make2(name, args);
2175  break;
2176  case OBJECT_FUNCTION:
2177  case OBJECT_PROCEDURE:
2178  case OBJECT_ROUTINE:
2179  case OBJECT_AGGREGATE:
2180  case OBJECT_OPERATOR:
2181  {
2183 
2184  owa->objname = name;
2185  owa->objargs = args;
2186  objnode = (Node *) owa;
2187  break;
2188  }
2189  case OBJECT_LARGEOBJECT:
2190  /* already handled above */
2191  break;
2192  /* no default, to let compiler warn about missing case */
2193  }
2194 
2195  if (objnode == NULL)
2196  elog(ERROR, "unrecognized object type: %d", type);
2197 
2198  addr = get_object_address(type, objnode,
2199  &relation, AccessShareLock, false);
2200 
2201  /* We don't need the relcache entry, thank you very much */
2202  if (relation)
2203  relation_close(relation, AccessShareLock);
2204 
2205  tupdesc = CreateTemplateTupleDesc(3, false);
2206  TupleDescInitEntry(tupdesc, (AttrNumber) 1, "classid",
2207  OIDOID, -1, 0);
2208  TupleDescInitEntry(tupdesc, (AttrNumber) 2, "objid",
2209  OIDOID, -1, 0);
2210  TupleDescInitEntry(tupdesc, (AttrNumber) 3, "objsubid",
2211  INT4OID, -1, 0);
2212  tupdesc = BlessTupleDesc(tupdesc);
2213 
2214  values[0] = ObjectIdGetDatum(addr.classId);
2215  values[1] = ObjectIdGetDatum(addr.objectId);
2216  values[2] = Int32GetDatum(addr.objectSubId);
2217  nulls[0] = false;
2218  nulls[1] = false;
2219  nulls[2] = false;
2220 
2221  htup = heap_form_tuple(tupdesc, values, nulls);
2222 
2224 }
2225 
2226 /*
2227  * Check ownership of an object previously identified by get_object_address.
2228  */
2229 void
2231  Node *object, Relation relation)
2232 {
2233  switch (objtype)
2234  {
2235  case OBJECT_INDEX:
2236  case OBJECT_SEQUENCE:
2237  case OBJECT_TABLE:
2238  case OBJECT_VIEW:
2239  case OBJECT_MATVIEW:
2240  case OBJECT_FOREIGN_TABLE:
2241  case OBJECT_COLUMN:
2242  case OBJECT_RULE:
2243  case OBJECT_TRIGGER:
2244  case OBJECT_POLICY:
2245  case OBJECT_TABCONSTRAINT:
2246  if (!pg_class_ownercheck(RelationGetRelid(relation), roleid))
2248  RelationGetRelationName(relation));
2249  break;
2250  case OBJECT_DATABASE:
2251  if (!pg_database_ownercheck(address.objectId, roleid))
2253  strVal((Value *) object));
2254  break;
2255  case OBJECT_TYPE:
2256  case OBJECT_DOMAIN:
2257  case OBJECT_ATTRIBUTE:
2258  case OBJECT_DOMCONSTRAINT:
2259  if (!pg_type_ownercheck(address.objectId, roleid))
2261  break;
2262  case OBJECT_AGGREGATE:
2263  case OBJECT_FUNCTION:
2264  case OBJECT_PROCEDURE:
2265  case OBJECT_ROUTINE:
2266  if (!pg_proc_ownercheck(address.objectId, roleid))
2268  NameListToString((castNode(ObjectWithArgs, object))->objname));
2269  break;
2270  case OBJECT_OPERATOR:
2271  if (!pg_oper_ownercheck(address.objectId, roleid))
2273  NameListToString((castNode(ObjectWithArgs, object))->objname));
2274  break;
2275  case OBJECT_SCHEMA:
2276  if (!pg_namespace_ownercheck(address.objectId, roleid))
2278  strVal((Value *) object));
2279  break;
2280  case OBJECT_COLLATION:
2281  if (!pg_collation_ownercheck(address.objectId, roleid))
2283  NameListToString(castNode(List, object)));
2284  break;
2285  case OBJECT_CONVERSION:
2286  if (!pg_conversion_ownercheck(address.objectId, roleid))
2288  NameListToString(castNode(List, object)));
2289  break;
2290  case OBJECT_EXTENSION:
2291  if (!pg_extension_ownercheck(address.objectId, roleid))
2293  strVal((Value *) object));
2294  break;
2295  case OBJECT_FDW:
2296  if (!pg_foreign_data_wrapper_ownercheck(address.objectId, roleid))
2298  strVal((Value *) object));
2299  break;
2300  case OBJECT_FOREIGN_SERVER:
2301  if (!pg_foreign_server_ownercheck(address.objectId, roleid))
2303  strVal((Value *) object));
2304  break;
2305  case OBJECT_EVENT_TRIGGER:
2306  if (!pg_event_trigger_ownercheck(address.objectId, roleid))
2308  strVal((Value *) object));
2309  break;
2310  case OBJECT_LANGUAGE:
2311  if (!pg_language_ownercheck(address.objectId, roleid))
2313  strVal((Value *) object));
2314  break;
2315  case OBJECT_OPCLASS:
2316  if (!pg_opclass_ownercheck(address.objectId, roleid))
2318  NameListToString(castNode(List, object)));
2319  break;
2320  case OBJECT_OPFAMILY:
2321  if (!pg_opfamily_ownercheck(address.objectId, roleid))
2323  NameListToString(castNode(List, object)));
2324  break;
2325  case OBJECT_LARGEOBJECT:
2326  if (!lo_compat_privileges &&
2327  !pg_largeobject_ownercheck(address.objectId, roleid))
2328  ereport(ERROR,
2329  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2330  errmsg("must be owner of large object %u",
2331  address.objectId)));
2332  break;
2333  case OBJECT_CAST:
2334  {
2335  /* We can only check permissions on the source/target types */
2336  TypeName *sourcetype = linitial_node(TypeName, castNode(List, object));
2337  TypeName *targettype = lsecond_node(TypeName, castNode(List, object));
2338  Oid sourcetypeid = typenameTypeId(NULL, sourcetype);
2339  Oid targettypeid = typenameTypeId(NULL, targettype);
2340 
2341  if (!pg_type_ownercheck(sourcetypeid, roleid)
2342  && !pg_type_ownercheck(targettypeid, roleid))
2343  ereport(ERROR,
2344  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2345  errmsg("must be owner of type %s or type %s",
2346  format_type_be(sourcetypeid),
2347  format_type_be(targettypeid))));
2348  }
2349  break;
2350  case OBJECT_PUBLICATION:
2351  if (!pg_publication_ownercheck(address.objectId, roleid))
2353  strVal((Value *) object));
2354  break;
2355  case OBJECT_SUBSCRIPTION:
2356  if (!pg_subscription_ownercheck(address.objectId, roleid))
2358  strVal((Value *) object));
2359  break;
2360  case OBJECT_TRANSFORM:
2361  {
2362  TypeName *typename = linitial_node(TypeName, castNode(List, object));
2363  Oid typeid = typenameTypeId(NULL, typename);
2364 
2365  if (!pg_type_ownercheck(typeid, roleid))
2367  }
2368  break;
2369  case OBJECT_TABLESPACE:
2370  if (!pg_tablespace_ownercheck(address.objectId, roleid))
2372  strVal((Value *) object));
2373  break;
2374  case OBJECT_TSDICTIONARY:
2375  if (!pg_ts_dict_ownercheck(address.objectId, roleid))
2377  NameListToString(castNode(List, object)));
2378  break;
2380  if (!pg_ts_config_ownercheck(address.objectId, roleid))
2382  NameListToString(castNode(List, object)));
2383  break;
2384  case OBJECT_ROLE:
2385 
2386  /*
2387  * We treat roles as being "owned" by those with CREATEROLE priv,
2388  * except that superusers are only owned by superusers.
2389  */
2390  if (superuser_arg(address.objectId))
2391  {
2392  if (!superuser_arg(roleid))
2393  ereport(ERROR,
2394  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2395  errmsg("must be superuser")));
2396  }
2397  else
2398  {
2399  if (!has_createrole_privilege(roleid))
2400  ereport(ERROR,
2401  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2402  errmsg("must have CREATEROLE privilege")));
2403  }
2404  break;
2405  case OBJECT_TSPARSER:
2406  case OBJECT_TSTEMPLATE:
2407  case OBJECT_ACCESS_METHOD:
2408  /* We treat these object types as being owned by superusers */
2409  if (!superuser_arg(roleid))
2410  ereport(ERROR,
2411  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2412  errmsg("must be superuser")));
2413  break;
2414  case OBJECT_STATISTIC_EXT:
2415  if (!pg_statistics_object_ownercheck(address.objectId, roleid))
2417  break;
2418  default:
2419  elog(ERROR, "unrecognized object type: %d",
2420  (int) objtype);
2421  }
2422 }
2423 
2424 /*
2425  * get_object_namespace
2426  *
2427  * Find the schema containing the specified object. For non-schema objects,
2428  * this function returns InvalidOid.
2429  */
2430 Oid
2432 {
2433  int cache;
2434  HeapTuple tuple;
2435  bool isnull;
2436  Oid oid;
2437  const ObjectPropertyType *property;
2438 
2439  /* If not owned by a namespace, just return InvalidOid. */
2440  property = get_object_property_data(address->classId);
2441  if (property->attnum_namespace == InvalidAttrNumber)
2442  return InvalidOid;
2443 
2444  /* Currently, we can only handle object types with system caches. */
2445  cache = property->oid_catcache_id;
2446  Assert(cache != -1);
2447 
2448  /* Fetch tuple from syscache and extract namespace attribute. */
2449  tuple = SearchSysCache1(cache, ObjectIdGetDatum(address->objectId));
2450  if (!HeapTupleIsValid(tuple))
2451  elog(ERROR, "cache lookup failed for cache %d oid %u",
2452  cache, address->objectId);
2453  oid = DatumGetObjectId(SysCacheGetAttr(cache,
2454  tuple,
2455  property->attnum_namespace,
2456  &isnull));
2457  Assert(!isnull);
2458  ReleaseSysCache(tuple);
2459 
2460  return oid;
2461 }
2462 
2463 /*
2464  * Return ObjectType for the given object type as given by
2465  * getObjectTypeDescription; if no valid ObjectType code exists, but it's a
2466  * possible output type from getObjectTypeDescription, return -1.
2467  * Otherwise, an error is thrown.
2468  */
2469 int
2470 read_objtype_from_string(const char *objtype)
2471 {
2472  int i;
2473 
2474  for (i = 0; i < lengthof(ObjectTypeMap); i++)
2475  {
2476  if (strcmp(ObjectTypeMap[i].tm_name, objtype) == 0)
2477  return ObjectTypeMap[i].tm_type;
2478  }
2479  ereport(ERROR,
2480  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2481  errmsg("unrecognized object type \"%s\"", objtype)));
2482 
2483  return -1; /* keep compiler quiet */
2484 }
2485 
2486 /*
2487  * Interfaces to reference fields of ObjectPropertyType
2488  */
2489 Oid
2491 {
2492  const ObjectPropertyType *prop = get_object_property_data(class_id);
2493 
2494  return prop->oid_index_oid;
2495 }
2496 
2497 int
2499 {
2500  const ObjectPropertyType *prop = get_object_property_data(class_id);
2501 
2502  return prop->oid_catcache_id;
2503 }
2504 
2505 int
2507 {
2508  const ObjectPropertyType *prop = get_object_property_data(class_id);
2509 
2510  return prop->name_catcache_id;
2511 }
2512 
2513 AttrNumber
2515 {
2516  const ObjectPropertyType *prop = get_object_property_data(class_id);
2517 
2518  return prop->attnum_name;
2519 }
2520 
2521 AttrNumber
2523 {
2524  const ObjectPropertyType *prop = get_object_property_data(class_id);
2525 
2526  return prop->attnum_namespace;
2527 }
2528 
2529 AttrNumber
2531 {
2532  const ObjectPropertyType *prop = get_object_property_data(class_id);
2533 
2534  return prop->attnum_owner;
2535 }
2536 
2537 AttrNumber
2539 {
2540  const ObjectPropertyType *prop = get_object_property_data(class_id);
2541 
2542  return prop->attnum_acl;
2543 }
2544 
2545 ObjectType
2546 get_object_type(Oid class_id, Oid object_id)
2547 {
2548  const ObjectPropertyType *prop = get_object_property_data(class_id);
2549 
2550  if (prop->objtype == OBJECT_TABLE)
2551  {
2552  /*
2553  * If the property data says it's a table, dig a little deeper to get
2554  * the real relation kind, so that callers can produce more precise
2555  * error messages.
2556  */
2557  return get_relkind_objtype(get_rel_relkind(object_id));
2558  }
2559  else
2560  return prop->objtype;
2561 }
2562 
2563 bool
2565 {
2566  const ObjectPropertyType *prop = get_object_property_data(class_id);
2567 
2568  return prop->is_nsp_name_unique;
2569 }
2570 
2571 /*
2572  * Return whether we have useful data for the given object class in the
2573  * ObjectProperty table.
2574  */
2575 bool
2577 {
2578  int index;
2579 
2580  for (index = 0; index < lengthof(ObjectProperty); index++)
2581  {
2582  if (ObjectProperty[index].class_oid == class_id)
2583  return true;
2584  }
2585 
2586  return false;
2587 }
2588 
2589 /*
2590  * Find ObjectProperty structure by class_id.
2591  */
2592 static const ObjectPropertyType *
2594 {
2595  static const ObjectPropertyType *prop_last = NULL;
2596  int index;
2597 
2598  /*
2599  * A shortcut to speed up multiple consecutive lookups of a particular
2600  * object class.
2601  */
2602  if (prop_last && prop_last->class_oid == class_id)
2603  return prop_last;
2604 
2605  for (index = 0; index < lengthof(ObjectProperty); index++)
2606  {
2607  if (ObjectProperty[index].class_oid == class_id)
2608  {
2609  prop_last = &ObjectProperty[index];
2610  return &ObjectProperty[index];
2611  }
2612  }
2613 
2614  ereport(ERROR,
2615  (errmsg_internal("unrecognized class ID: %u", class_id)));
2616 
2617  return NULL; /* keep MSC compiler happy */
2618 }
2619 
2620 /*
2621  * Return a copy of the tuple for the object with the given object OID, from
2622  * the given catalog (which must have been opened by the caller and suitably
2623  * locked). NULL is returned if the OID is not found.
2624  *
2625  * We try a syscache first, if available.
2626  */
2627 HeapTuple
2629 {
2630  HeapTuple tuple;
2631  Oid classId = RelationGetRelid(catalog);
2632  int oidCacheId = get_object_catcache_oid(classId);
2633 
2634  if (oidCacheId > 0)
2635  {
2636  tuple = SearchSysCacheCopy1(oidCacheId, ObjectIdGetDatum(objectId));
2637  if (!HeapTupleIsValid(tuple)) /* should not happen */
2638  return NULL;
2639  }
2640  else
2641  {
2642  Oid oidIndexId = get_object_oid_index(classId);
2643  SysScanDesc scan;
2644  ScanKeyData skey;
2645 
2646  Assert(OidIsValid(oidIndexId));
2647 
2648  ScanKeyInit(&skey,
2650  BTEqualStrategyNumber, F_OIDEQ,
2651  ObjectIdGetDatum(objectId));
2652 
2653  scan = systable_beginscan(catalog, oidIndexId, true,
2654  NULL, 1, &skey);
2655  tuple = systable_getnext(scan);
2656  if (!HeapTupleIsValid(tuple))
2657  {
2658  systable_endscan(scan);
2659  return NULL;
2660  }
2661  tuple = heap_copytuple(tuple);
2662 
2663  systable_endscan(scan);
2664  }
2665 
2666  return tuple;
2667 }
2668 
2669 /*
2670  * getObjectDescription: build an object description for messages
2671  *
2672  * The result is a palloc'd string.
2673  */
2674 char *
2676 {
2678 
2679  initStringInfo(&buffer);
2680 
2681  switch (getObjectClass(object))
2682  {
2683  case OCLASS_CLASS:
2684  getRelationDescription(&buffer, object->objectId);
2685  if (object->objectSubId != 0)
2686  appendStringInfo(&buffer, _(" column %s"),
2687  get_attname(object->objectId,
2688  object->objectSubId,
2689  false));
2690  break;
2691 
2692  case OCLASS_PROC:
2693  appendStringInfo(&buffer, _("function %s"),
2694  format_procedure(object->objectId));
2695  break;
2696 
2697  case OCLASS_TYPE:
2698  appendStringInfo(&buffer, _("type %s"),
2699  format_type_be(object->objectId));
2700  break;
2701 
2702  case OCLASS_CAST:
2703  {
2704  Relation castDesc;
2705  ScanKeyData skey[1];
2706  SysScanDesc rcscan;
2707  HeapTuple tup;
2708  Form_pg_cast castForm;
2709 
2711 
2712  ScanKeyInit(&skey[0],
2714  BTEqualStrategyNumber, F_OIDEQ,
2715  ObjectIdGetDatum(object->objectId));
2716 
2717  rcscan = systable_beginscan(castDesc, CastOidIndexId, true,
2718  NULL, 1, skey);
2719 
2720  tup = systable_getnext(rcscan);
2721 
2722  if (!HeapTupleIsValid(tup))
2723  elog(ERROR, "could not find tuple for cast %u",
2724  object->objectId);
2725 
2726  castForm = (Form_pg_cast) GETSTRUCT(tup);
2727 
2728  appendStringInfo(&buffer, _("cast from %s to %s"),
2729  format_type_be(castForm->castsource),
2730  format_type_be(castForm->casttarget));
2731 
2732  systable_endscan(rcscan);
2733  heap_close(castDesc, AccessShareLock);
2734  break;
2735  }
2736 
2737  case OCLASS_COLLATION:
2738  {
2739  HeapTuple collTup;
2740  Form_pg_collation coll;
2741 
2742  collTup = SearchSysCache1(COLLOID,
2743  ObjectIdGetDatum(object->objectId));
2744  if (!HeapTupleIsValid(collTup))
2745  elog(ERROR, "cache lookup failed for collation %u",
2746  object->objectId);
2747  coll = (Form_pg_collation) GETSTRUCT(collTup);
2748  appendStringInfo(&buffer, _("collation %s"),
2749  NameStr(coll->collname));
2750  ReleaseSysCache(collTup);
2751  break;
2752  }
2753 
2754  case OCLASS_CONSTRAINT:
2755  {
2756  HeapTuple conTup;
2757  Form_pg_constraint con;
2758 
2759  conTup = SearchSysCache1(CONSTROID,
2760  ObjectIdGetDatum(object->objectId));
2761  if (!HeapTupleIsValid(conTup))
2762  elog(ERROR, "cache lookup failed for constraint %u",
2763  object->objectId);
2764  con = (Form_pg_constraint) GETSTRUCT(conTup);
2765 
2766  if (OidIsValid(con->conrelid))
2767  {
2768  StringInfoData rel;
2769 
2770  initStringInfo(&rel);
2771  getRelationDescription(&rel, con->conrelid);
2772  appendStringInfo(&buffer, _("constraint %s on %s"),
2773  NameStr(con->conname), rel.data);
2774  pfree(rel.data);
2775  }
2776  else
2777  {
2778  appendStringInfo(&buffer, _("constraint %s"),
2779  NameStr(con->conname));
2780  }
2781 
2782  ReleaseSysCache(conTup);
2783  break;
2784  }
2785 
2786  case OCLASS_CONVERSION:
2787  {
2788  HeapTuple conTup;
2789 
2790  conTup = SearchSysCache1(CONVOID,
2791  ObjectIdGetDatum(object->objectId));
2792  if (!HeapTupleIsValid(conTup))
2793  elog(ERROR, "cache lookup failed for conversion %u",
2794  object->objectId);
2795  appendStringInfo(&buffer, _("conversion %s"),
2796  NameStr(((Form_pg_conversion) GETSTRUCT(conTup))->conname));
2797  ReleaseSysCache(conTup);
2798  break;
2799  }
2800 
2801  case OCLASS_DEFAULT:
2802  {
2803  Relation attrdefDesc;
2804  ScanKeyData skey[1];
2805  SysScanDesc adscan;
2806  HeapTuple tup;
2807  Form_pg_attrdef attrdef;
2808  ObjectAddress colobject;
2809 
2811 
2812  ScanKeyInit(&skey[0],
2814  BTEqualStrategyNumber, F_OIDEQ,
2815  ObjectIdGetDatum(object->objectId));
2816 
2817  adscan = systable_beginscan(attrdefDesc, AttrDefaultOidIndexId,
2818  true, NULL, 1, skey);
2819 
2820  tup = systable_getnext(adscan);
2821 
2822  if (!HeapTupleIsValid(tup))
2823  elog(ERROR, "could not find tuple for attrdef %u",
2824  object->objectId);
2825 
2826  attrdef = (Form_pg_attrdef) GETSTRUCT(tup);
2827 
2828  colobject.classId = RelationRelationId;
2829  colobject.objectId = attrdef->adrelid;
2830  colobject.objectSubId = attrdef->adnum;
2831 
2832  appendStringInfo(&buffer, _("default for %s"),
2833  getObjectDescription(&colobject));
2834 
2835  systable_endscan(adscan);
2836  heap_close(attrdefDesc, AccessShareLock);
2837  break;
2838  }
2839 
2840  case OCLASS_LANGUAGE:
2841  appendStringInfo(&buffer, _("language %s"),
2842  get_language_name(object->objectId, false));
2843  break;
2844 
2845  case OCLASS_LARGEOBJECT:
2846  appendStringInfo(&buffer, _("large object %u"),
2847  object->objectId);
2848  break;
2849 
2850  case OCLASS_OPERATOR:
2851  appendStringInfo(&buffer, _("operator %s"),
2852  format_operator(object->objectId));
2853  break;
2854 
2855  case OCLASS_OPCLASS:
2856  {
2857  HeapTuple opcTup;
2858  Form_pg_opclass opcForm;
2859  HeapTuple amTup;
2860  Form_pg_am amForm;
2861  char *nspname;
2862 
2863  opcTup = SearchSysCache1(CLAOID,
2864  ObjectIdGetDatum(object->objectId));
2865  if (!HeapTupleIsValid(opcTup))
2866  elog(ERROR, "cache lookup failed for opclass %u",
2867  object->objectId);
2868  opcForm = (Form_pg_opclass) GETSTRUCT(opcTup);
2869 
2870  amTup = SearchSysCache1(AMOID,
2871  ObjectIdGetDatum(opcForm->opcmethod));
2872  if (!HeapTupleIsValid(amTup))
2873  elog(ERROR, "cache lookup failed for access method %u",
2874  opcForm->opcmethod);
2875  amForm = (Form_pg_am) GETSTRUCT(amTup);
2876 
2877  /* Qualify the name if not visible in search path */
2878  if (OpclassIsVisible(object->objectId))
2879  nspname = NULL;
2880  else
2881  nspname = get_namespace_name(opcForm->opcnamespace);
2882 
2883  appendStringInfo(&buffer, _("operator class %s for access method %s"),
2885  NameStr(opcForm->opcname)),
2886  NameStr(amForm->amname));
2887 
2888  ReleaseSysCache(amTup);
2889  ReleaseSysCache(opcTup);
2890  break;
2891  }
2892 
2893  case OCLASS_OPFAMILY:
2894  getOpFamilyDescription(&buffer, object->objectId);
2895  break;
2896 
2897  case OCLASS_AM:
2898  {
2899  HeapTuple tup;
2900 
2901  tup = SearchSysCache1(AMOID,
2902  ObjectIdGetDatum(object->objectId));
2903  if (!HeapTupleIsValid(tup))
2904  elog(ERROR, "cache lookup failed for access method %u",
2905  object->objectId);
2906  appendStringInfo(&buffer, _("access method %s"),
2907  NameStr(((Form_pg_am) GETSTRUCT(tup))->amname));
2908  ReleaseSysCache(tup);
2909  break;
2910  }
2911 
2912  case OCLASS_AMOP:
2913  {
2914  Relation amopDesc;
2915  HeapTuple tup;
2916  ScanKeyData skey[1];
2917  SysScanDesc amscan;
2918  Form_pg_amop amopForm;
2919  StringInfoData opfam;
2920 
2922  AccessShareLock);
2923 
2924  ScanKeyInit(&skey[0],
2926  BTEqualStrategyNumber, F_OIDEQ,
2927  ObjectIdGetDatum(object->objectId));
2928 
2929  amscan = systable_beginscan(amopDesc, AccessMethodOperatorOidIndexId, true,
2930  NULL, 1, skey);
2931 
2932  tup = systable_getnext(amscan);
2933 
2934  if (!HeapTupleIsValid(tup))
2935  elog(ERROR, "could not find tuple for amop entry %u",
2936  object->objectId);
2937 
2938  amopForm = (Form_pg_amop) GETSTRUCT(tup);
2939 
2940  initStringInfo(&opfam);
2941  getOpFamilyDescription(&opfam, amopForm->amopfamily);
2942 
2943  /*------
2944  translator: %d is the operator strategy (a number), the
2945  first two %s's are data type names, the third %s is the
2946  description of the operator family, and the last %s is the
2947  textual form of the operator with arguments. */
2948  appendStringInfo(&buffer, _("operator %d (%s, %s) of %s: %s"),
2949  amopForm->amopstrategy,
2950  format_type_be(amopForm->amoplefttype),
2951  format_type_be(amopForm->amoprighttype),
2952  opfam.data,
2953  format_operator(amopForm->amopopr));
2954 
2955  pfree(opfam.data);
2956 
2957  systable_endscan(amscan);
2958  heap_close(amopDesc, AccessShareLock);
2959  break;
2960  }
2961 
2962  case OCLASS_AMPROC:
2963  {
2964  Relation amprocDesc;
2965  ScanKeyData skey[1];
2966  SysScanDesc amscan;
2967  HeapTuple tup;
2968  Form_pg_amproc amprocForm;
2969  StringInfoData opfam;
2970 
2972  AccessShareLock);
2973 
2974  ScanKeyInit(&skey[0],
2976  BTEqualStrategyNumber, F_OIDEQ,
2977  ObjectIdGetDatum(object->objectId));
2978 
2979  amscan = systable_beginscan(amprocDesc, AccessMethodProcedureOidIndexId, true,
2980  NULL, 1, skey);
2981 
2982  tup = systable_getnext(amscan);
2983 
2984  if (!HeapTupleIsValid(tup))
2985  elog(ERROR, "could not find tuple for amproc entry %u",
2986  object->objectId);
2987 
2988  amprocForm = (Form_pg_amproc) GETSTRUCT(tup);
2989 
2990  initStringInfo(&opfam);
2991  getOpFamilyDescription(&opfam, amprocForm->amprocfamily);
2992 
2993  /*------
2994  translator: %d is the function number, the first two %s's
2995  are data type names, the third %s is the description of the
2996  operator family, and the last %s is the textual form of the
2997  function with arguments. */
2998  appendStringInfo(&buffer, _("function %d (%s, %s) of %s: %s"),
2999  amprocForm->amprocnum,
3000  format_type_be(amprocForm->amproclefttype),
3001  format_type_be(amprocForm->amprocrighttype),
3002  opfam.data,
3003  format_procedure(amprocForm->amproc));
3004 
3005  pfree(opfam.data);
3006 
3007  systable_endscan(amscan);
3008  heap_close(amprocDesc, AccessShareLock);
3009  break;
3010  }
3011 
3012  case OCLASS_REWRITE:
3013  {
3014  Relation ruleDesc;
3015  ScanKeyData skey[1];
3016  SysScanDesc rcscan;
3017  HeapTuple tup;
3019 
3021 
3022  ScanKeyInit(&skey[0],
3024  BTEqualStrategyNumber, F_OIDEQ,
3025  ObjectIdGetDatum(object->objectId));
3026 
3027  rcscan = systable_beginscan(ruleDesc, RewriteOidIndexId, true,
3028  NULL, 1, skey);
3029 
3030  tup = systable_getnext(rcscan);
3031 
3032  if (!HeapTupleIsValid(tup))
3033  elog(ERROR, "could not find tuple for rule %u",
3034  object->objectId);
3035 
3036  rule = (Form_pg_rewrite) GETSTRUCT(tup);
3037 
3038  appendStringInfo(&buffer, _("rule %s on "),
3039  NameStr(rule->rulename));
3040  getRelationDescription(&buffer, rule->ev_class);
3041 
3042  systable_endscan(rcscan);
3043  heap_close(ruleDesc, AccessShareLock);
3044  break;
3045  }
3046 
3047  case OCLASS_TRIGGER:
3048  {
3049  Relation trigDesc;
3050  ScanKeyData skey[1];
3051  SysScanDesc tgscan;
3052  HeapTuple tup;
3053  Form_pg_trigger trig;
3054 
3056 
3057  ScanKeyInit(&skey[0],
3059  BTEqualStrategyNumber, F_OIDEQ,
3060  ObjectIdGetDatum(object->objectId));
3061 
3062  tgscan = systable_beginscan(trigDesc, TriggerOidIndexId, true,
3063  NULL, 1, skey);
3064 
3065  tup = systable_getnext(tgscan);
3066 
3067  if (!HeapTupleIsValid(tup))
3068  elog(ERROR, "could not find tuple for trigger %u",
3069  object->objectId);
3070 
3071  trig = (Form_pg_trigger) GETSTRUCT(tup);
3072 
3073  appendStringInfo(&buffer, _("trigger %s on "),
3074  NameStr(trig->tgname));
3075  getRelationDescription(&buffer, trig->tgrelid);
3076 
3077  systable_endscan(tgscan);
3078  heap_close(trigDesc, AccessShareLock);
3079  break;
3080  }
3081 
3082  case OCLASS_SCHEMA:
3083  {
3084  char *nspname;
3085 
3086  nspname = get_namespace_name(object->objectId);
3087  if (!nspname)
3088  elog(ERROR, "cache lookup failed for namespace %u",
3089  object->objectId);
3090  appendStringInfo(&buffer, _("schema %s"), nspname);
3091  break;
3092  }
3093 
3094  case OCLASS_STATISTIC_EXT:
3095  {
3096  HeapTuple stxTup;
3097  Form_pg_statistic_ext stxForm;
3098 
3099  stxTup = SearchSysCache1(STATEXTOID,
3100  ObjectIdGetDatum(object->objectId));
3101  if (!HeapTupleIsValid(stxTup))
3102  elog(ERROR, "could not find tuple for statistics object %u",
3103  object->objectId);
3104 
3105  stxForm = (Form_pg_statistic_ext) GETSTRUCT(stxTup);
3106 
3107  appendStringInfo(&buffer, _("statistics object %s"),
3108  NameStr(stxForm->stxname));
3109 
3110  ReleaseSysCache(stxTup);
3111  break;
3112  }
3113 
3114  case OCLASS_TSPARSER:
3115  {
3116  HeapTuple tup;
3117 
3119  ObjectIdGetDatum(object->objectId));
3120  if (!HeapTupleIsValid(tup))
3121  elog(ERROR, "cache lookup failed for text search parser %u",
3122  object->objectId);
3123  appendStringInfo(&buffer, _("text search parser %s"),
3124  NameStr(((Form_pg_ts_parser) GETSTRUCT(tup))->prsname));
3125  ReleaseSysCache(tup);
3126  break;
3127  }
3128 
3129  case OCLASS_TSDICT:
3130  {
3131  HeapTuple tup;
3132 
3133  tup = SearchSysCache1(TSDICTOID,
3134  ObjectIdGetDatum(object->objectId));
3135  if (!HeapTupleIsValid(tup))
3136  elog(ERROR, "cache lookup failed for text search dictionary %u",
3137  object->objectId);
3138  appendStringInfo(&buffer, _("text search dictionary %s"),
3139  NameStr(((Form_pg_ts_dict) GETSTRUCT(tup))->dictname));
3140  ReleaseSysCache(tup);
3141  break;
3142  }
3143 
3144  case OCLASS_TSTEMPLATE:
3145  {
3146  HeapTuple tup;
3147 
3149  ObjectIdGetDatum(object->objectId));
3150  if (!HeapTupleIsValid(tup))
3151  elog(ERROR, "cache lookup failed for text search template %u",
3152  object->objectId);
3153  appendStringInfo(&buffer, _("text search template %s"),
3154  NameStr(((Form_pg_ts_template) GETSTRUCT(tup))->tmplname));
3155  ReleaseSysCache(tup);
3156  break;
3157  }
3158 
3159  case OCLASS_TSCONFIG:
3160  {
3161  HeapTuple tup;
3162 
3164  ObjectIdGetDatum(object->objectId));
3165  if (!HeapTupleIsValid(tup))
3166  elog(ERROR, "cache lookup failed for text search configuration %u",
3167  object->objectId);
3168  appendStringInfo(&buffer, _("text search configuration %s"),
3169  NameStr(((Form_pg_ts_config) GETSTRUCT(tup))->cfgname));
3170  ReleaseSysCache(tup);
3171  break;
3172  }
3173 
3174  case OCLASS_ROLE:
3175  {
3176  appendStringInfo(&buffer, _("role %s"),
3177  GetUserNameFromId(object->objectId, false));
3178  break;
3179  }
3180 
3181  case OCLASS_DATABASE:
3182  {
3183  char *datname;
3184 
3185  datname = get_database_name(object->objectId);
3186  if (!datname)
3187  elog(ERROR, "cache lookup failed for database %u",
3188  object->objectId);
3189  appendStringInfo(&buffer, _("database %s"), datname);
3190  break;
3191  }
3192 
3193  case OCLASS_TBLSPACE:
3194  {
3195  char *tblspace;
3196 
3197  tblspace = get_tablespace_name(object->objectId);
3198  if (!tblspace)
3199  elog(ERROR, "cache lookup failed for tablespace %u",
3200  object->objectId);
3201  appendStringInfo(&buffer, _("tablespace %s"), tblspace);
3202  break;
3203  }
3204 
3205  case OCLASS_FDW:
3206  {
3207  ForeignDataWrapper *fdw;
3208 
3209  fdw = GetForeignDataWrapper(object->objectId);
3210  appendStringInfo(&buffer, _("foreign-data wrapper %s"), fdw->fdwname);
3211  break;
3212  }
3213 
3214  case OCLASS_FOREIGN_SERVER:
3215  {
3216  ForeignServer *srv;
3217 
3218  srv = GetForeignServer(object->objectId);
3219  appendStringInfo(&buffer, _("server %s"), srv->servername);
3220  break;
3221  }
3222 
3223  case OCLASS_USER_MAPPING:
3224  {
3225  HeapTuple tup;
3226  Oid useid;
3227  char *usename;
3228  Form_pg_user_mapping umform;
3229  ForeignServer *srv;
3230 
3232  ObjectIdGetDatum(object->objectId));
3233  if (!HeapTupleIsValid(tup))
3234  elog(ERROR, "cache lookup failed for user mapping %u",
3235  object->objectId);
3236  umform = (Form_pg_user_mapping) GETSTRUCT(tup);
3237  useid = umform->umuser;
3238  srv = GetForeignServer(umform->umserver);
3239 
3240  ReleaseSysCache(tup);
3241 
3242  if (OidIsValid(useid))
3243  usename = GetUserNameFromId(useid, false);
3244  else
3245  usename = "public";
3246 
3247  appendStringInfo(&buffer, _("user mapping for %s on server %s"), usename,
3248  srv->servername);
3249  break;
3250  }
3251 
3252  case OCLASS_DEFACL:
3253  {
3254  Relation defaclrel;
3255  ScanKeyData skey[1];
3256  SysScanDesc rcscan;
3257  HeapTuple tup;
3258  Form_pg_default_acl defacl;
3259 
3261 
3262  ScanKeyInit(&skey[0],
3264  BTEqualStrategyNumber, F_OIDEQ,
3265  ObjectIdGetDatum(object->objectId));
3266 
3267  rcscan = systable_beginscan(defaclrel, DefaultAclOidIndexId,
3268  true, NULL, 1, skey);
3269 
3270  tup = systable_getnext(rcscan);
3271 
3272  if (!HeapTupleIsValid(tup))
3273  elog(ERROR, "could not find tuple for default ACL %u",
3274  object->objectId);
3275 
3276  defacl = (Form_pg_default_acl) GETSTRUCT(tup);
3277 
3278  switch (defacl->defaclobjtype)
3279  {
3280  case DEFACLOBJ_RELATION:
3281  appendStringInfo(&buffer,
3282  _("default privileges on new relations belonging to role %s"),
3283  GetUserNameFromId(defacl->defaclrole, false));
3284  break;
3285  case DEFACLOBJ_SEQUENCE:
3286  appendStringInfo(&buffer,
3287  _("default privileges on new sequences belonging to role %s"),
3288  GetUserNameFromId(defacl->defaclrole, false));
3289  break;
3290  case DEFACLOBJ_FUNCTION:
3291  appendStringInfo(&buffer,
3292  _("default privileges on new functions belonging to role %s"),
3293  GetUserNameFromId(defacl->defaclrole, false));
3294  break;
3295  case DEFACLOBJ_TYPE:
3296  appendStringInfo(&buffer,
3297  _("default privileges on new types belonging to role %s"),
3298  GetUserNameFromId(defacl->defaclrole, false));
3299  break;
3300  case DEFACLOBJ_NAMESPACE:
3301  appendStringInfo(&buffer,
3302  _("default privileges on new schemas belonging to role %s"),
3303  GetUserNameFromId(defacl->defaclrole, false));
3304  break;
3305  default:
3306  /* shouldn't get here */
3307  appendStringInfo(&buffer,
3308  _("default privileges belonging to role %s"),
3309  GetUserNameFromId(defacl->defaclrole, false));
3310  break;
3311  }
3312 
3313  if (OidIsValid(defacl->defaclnamespace))
3314  {
3315  appendStringInfo(&buffer,
3316  _(" in schema %s"),
3317  get_namespace_name(defacl->defaclnamespace));
3318  }
3319 
3320  systable_endscan(rcscan);
3321  heap_close(defaclrel, AccessShareLock);
3322  break;
3323  }
3324 
3325  case OCLASS_EXTENSION:
3326  {
3327  char *extname;
3328 
3329  extname = get_extension_name(object->objectId);
3330  if (!extname)
3331  elog(ERROR, "cache lookup failed for extension %u",
3332  object->objectId);
3333  appendStringInfo(&buffer, _("extension %s"), extname);
3334  break;
3335  }
3336 
3337  case OCLASS_EVENT_TRIGGER:
3338  {
3339  HeapTuple tup;
3340 
3342  ObjectIdGetDatum(object->objectId));
3343  if (!HeapTupleIsValid(tup))
3344  elog(ERROR, "cache lookup failed for event trigger %u",
3345  object->objectId);
3346  appendStringInfo(&buffer, _("event trigger %s"),
3347  NameStr(((Form_pg_event_trigger) GETSTRUCT(tup))->evtname));
3348  ReleaseSysCache(tup);
3349  break;
3350  }
3351 
3352  case OCLASS_POLICY:
3353  {
3354  Relation policy_rel;
3355  ScanKeyData skey[1];
3356  SysScanDesc sscan;
3357  HeapTuple tuple;
3358  Form_pg_policy form_policy;
3359 
3361 
3362  ScanKeyInit(&skey[0],
3364  BTEqualStrategyNumber, F_OIDEQ,
3365  ObjectIdGetDatum(object->objectId));
3366 
3367  sscan = systable_beginscan(policy_rel, PolicyOidIndexId,
3368  true, NULL, 1, skey);
3369 
3370  tuple = systable_getnext(sscan);
3371 
3372  if (!HeapTupleIsValid(tuple))
3373  elog(ERROR, "could not find tuple for policy %u",
3374  object->objectId);
3375 
3376  form_policy = (Form_pg_policy) GETSTRUCT(tuple);
3377 
3378  appendStringInfo(&buffer, _("policy %s on "),
3379  NameStr(form_policy->polname));
3380  getRelationDescription(&buffer, form_policy->polrelid);
3381 
3382  systable_endscan(sscan);
3383  heap_close(policy_rel, AccessShareLock);
3384  break;
3385  }
3386 
3387  case OCLASS_PUBLICATION:
3388  {
3389  appendStringInfo(&buffer, _("publication %s"),
3390  get_publication_name(object->objectId));
3391  break;
3392  }
3393 
3395  {
3396  HeapTuple tup;
3397  char *pubname;
3398  Form_pg_publication_rel prform;
3399 
3401  ObjectIdGetDatum(object->objectId));
3402  if (!HeapTupleIsValid(tup))
3403  elog(ERROR, "cache lookup failed for publication table %u",
3404  object->objectId);
3405 
3406  prform = (Form_pg_publication_rel) GETSTRUCT(tup);
3407  pubname = get_publication_name(prform->prpubid);
3408 
3409  appendStringInfo(&buffer, _("publication table %s in publication %s"),
3410  get_rel_name(prform->prrelid), pubname);
3411  ReleaseSysCache(tup);
3412  break;
3413  }
3414 
3415  case OCLASS_SUBSCRIPTION:
3416  {
3417  appendStringInfo(&buffer, _("subscription %s"),
3418  get_subscription_name(object->objectId));
3419  break;
3420  }
3421 
3422  case OCLASS_TRANSFORM:
3423  {
3424  HeapTuple trfTup;
3425  Form_pg_transform trfForm;
3426 
3427  trfTup = SearchSysCache1(TRFOID,
3428  ObjectIdGetDatum(object->objectId));
3429  if (!HeapTupleIsValid(trfTup))
3430  elog(ERROR, "could not find tuple for transform %u",
3431  object->objectId);
3432 
3433  trfForm = (Form_pg_transform) GETSTRUCT(trfTup);
3434 
3435  appendStringInfo(&buffer, _("transform for %s language %s"),
3436  format_type_be(trfForm->trftype),
3437  get_language_name(trfForm->trflang, false));
3438 
3439  ReleaseSysCache(trfTup);
3440  break;
3441  }
3442 
3443  /*
3444  * There's intentionally no default: case here; we want the
3445  * compiler to warn if a new OCLASS hasn't been handled above.
3446  */
3447  }
3448 
3449  return buffer.data;
3450 }
3451 
3452 /*
3453  * getObjectDescriptionOids: as above, except the object is specified by Oids
3454  */
3455 char *
3457 {
3458  ObjectAddress address;
3459 
3460  address.classId = classid;
3461  address.objectId = objid;
3462  address.objectSubId = 0;
3463 
3464  return getObjectDescription(&address);
3465 }
3466 
3467 /*
3468  * subroutine for getObjectDescription: describe a relation
3469  */
3470 static void
3472 {
3473  HeapTuple relTup;
3474  Form_pg_class relForm;
3475  char *nspname;
3476  char *relname;
3477 
3478  relTup = SearchSysCache1(RELOID,
3479  ObjectIdGetDatum(relid));
3480  if (!HeapTupleIsValid(relTup))
3481  elog(ERROR, "cache lookup failed for relation %u", relid);
3482  relForm = (Form_pg_class) GETSTRUCT(relTup);
3483 
3484  /* Qualify the name if not visible in search path */
3485  if (RelationIsVisible(relid))
3486  nspname = NULL;
3487  else
3488  nspname = get_namespace_name(relForm->relnamespace);
3489 
3490  relname = quote_qualified_identifier(nspname, NameStr(relForm->relname));
3491 
3492  switch (relForm->relkind)
3493  {
3494  case RELKIND_RELATION:
3496  appendStringInfo(buffer, _("table %s"),
3497  relname);
3498  break;
3499  case RELKIND_INDEX:
3501  appendStringInfo(buffer, _("index %s"),
3502  relname);
3503  break;
3504  case RELKIND_SEQUENCE:
3505  appendStringInfo(buffer, _("sequence %s"),
3506  relname);
3507  break;
3508  case RELKIND_TOASTVALUE:
3509  appendStringInfo(buffer, _("toast table %s"),
3510  relname);
3511  break;
3512  case RELKIND_VIEW:
3513  appendStringInfo(buffer, _("view %s"),
3514  relname);
3515  break;
3516  case RELKIND_MATVIEW:
3517  appendStringInfo(buffer, _("materialized view %s"),
3518  relname);
3519  break;
3521  appendStringInfo(buffer, _("composite type %s"),
3522  relname);
3523  break;
3524  case RELKIND_FOREIGN_TABLE:
3525  appendStringInfo(buffer, _("foreign table %s"),
3526  relname);
3527  break;
3528  default:
3529  /* shouldn't get here */
3530  appendStringInfo(buffer, _("relation %s"),
3531  relname);
3532  break;
3533  }
3534 
3535  ReleaseSysCache(relTup);
3536 }
3537 
3538 /*
3539  * subroutine for getObjectDescription: describe an operator family
3540  */
3541 static void
3543 {
3544  HeapTuple opfTup;
3545  Form_pg_opfamily opfForm;
3546  HeapTuple amTup;
3547  Form_pg_am amForm;
3548  char *nspname;
3549 
3550  opfTup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfid));
3551  if (!HeapTupleIsValid(opfTup))
3552  elog(ERROR, "cache lookup failed for opfamily %u", opfid);
3553  opfForm = (Form_pg_opfamily) GETSTRUCT(opfTup);
3554 
3555  amTup = SearchSysCache1(AMOID, ObjectIdGetDatum(opfForm->opfmethod));
3556  if (!HeapTupleIsValid(amTup))
3557  elog(ERROR, "cache lookup failed for access method %u",
3558  opfForm->opfmethod);
3559  amForm = (Form_pg_am) GETSTRUCT(amTup);
3560 
3561  /* Qualify the name if not visible in search path */
3562  if (OpfamilyIsVisible(opfid))
3563  nspname = NULL;
3564  else
3565  nspname = get_namespace_name(opfForm->opfnamespace);
3566 
3567  appendStringInfo(buffer, _("operator family %s for access method %s"),
3569  NameStr(opfForm->opfname)),
3570  NameStr(amForm->amname));
3571 
3572  ReleaseSysCache(amTup);
3573  ReleaseSysCache(opfTup);
3574 }
3575 
3576 /*
3577  * SQL-level callable version of getObjectDescription
3578  */
3579 Datum
3581 {
3582  Oid classid = PG_GETARG_OID(0);
3583  Oid objid = PG_GETARG_OID(1);
3584  int32 objsubid = PG_GETARG_INT32(2);
3585  char *description;
3586  ObjectAddress address;
3587 
3588  /* for "pinned" items in pg_depend, return null */
3589  if (!OidIsValid(classid) && !OidIsValid(objid))
3590  PG_RETURN_NULL();
3591 
3592  address.classId = classid;
3593  address.objectId = objid;
3594  address.objectSubId = objsubid;
3595 
3596  description = getObjectDescription(&address);
3597  PG_RETURN_TEXT_P(cstring_to_text(description));
3598 }
3599 
3600 /*
3601  * SQL-level callable function to obtain object type + identity
3602  */
3603 Datum
3605 {
3606  Oid classid = PG_GETARG_OID(0);
3607  Oid objid = PG_GETARG_OID(1);
3608  int32 objsubid = PG_GETARG_INT32(2);
3609  Oid schema_oid = InvalidOid;
3610  const char *objname = NULL;
3611  ObjectAddress address;
3612  Datum values[4];
3613  bool nulls[4];
3614  TupleDesc tupdesc;
3615  HeapTuple htup;
3616 
3617  address.classId = classid;
3618  address.objectId = objid;
3619  address.objectSubId = objsubid;
3620 
3621  /*
3622  * Construct a tuple descriptor for the result row. This must match this
3623  * function's pg_proc entry!
3624  */
3625  tupdesc = CreateTemplateTupleDesc(4, false);
3626  TupleDescInitEntry(tupdesc, (AttrNumber) 1, "type",
3627  TEXTOID, -1, 0);
3628  TupleDescInitEntry(tupdesc, (AttrNumber) 2, "schema",
3629  TEXTOID, -1, 0);
3630  TupleDescInitEntry(tupdesc, (AttrNumber) 3, "name",
3631  TEXTOID, -1, 0);
3632  TupleDescInitEntry(tupdesc, (AttrNumber) 4, "identity",
3633  TEXTOID, -1, 0);
3634 
3635  tupdesc = BlessTupleDesc(tupdesc);
3636 
3637  if (is_objectclass_supported(address.classId))
3638  {
3639  HeapTuple objtup;
3640  Relation catalog = heap_open(address.classId, AccessShareLock);
3641 
3642  objtup = get_catalog_object_by_oid(catalog, address.objectId);
3643  if (objtup != NULL)
3644  {
3645  bool isnull;
3646  AttrNumber nspAttnum;
3647  AttrNumber nameAttnum;
3648 
3649  nspAttnum = get_object_attnum_namespace(address.classId);
3650  if (nspAttnum != InvalidAttrNumber)
3651  {
3652  schema_oid = heap_getattr(objtup, nspAttnum,
3653  RelationGetDescr(catalog), &isnull);
3654  if (isnull)
3655  elog(ERROR, "invalid null namespace in object %u/%u/%d",
3656  address.classId, address.objectId, address.objectSubId);
3657  }
3658 
3659  /*
3660  * We only return the object name if it can be used (together with
3661  * the schema name, if any) as a unique identifier.
3662  */
3663  if (get_object_namensp_unique(address.classId))
3664  {
3665  nameAttnum = get_object_attnum_name(address.classId);
3666  if (nameAttnum != InvalidAttrNumber)
3667  {
3668  Datum nameDatum;
3669 
3670  nameDatum = heap_getattr(objtup, nameAttnum,
3671  RelationGetDescr(catalog), &isnull);
3672  if (isnull)
3673  elog(ERROR, "invalid null name in object %u/%u/%d",
3674  address.classId, address.objectId, address.objectSubId);
3675  objname = quote_identifier(NameStr(*(DatumGetName(nameDatum))));
3676  }
3677  }
3678  }
3679 
3680  heap_close(catalog, AccessShareLock);
3681  }
3682 
3683  /* object type */
3684  values[0] = CStringGetTextDatum(getObjectTypeDescription(&address));
3685  nulls[0] = false;
3686 
3687  /* schema name */
3688  if (OidIsValid(schema_oid))
3689  {
3690  const char *schema = quote_identifier(get_namespace_name(schema_oid));
3691 
3692  values[1] = CStringGetTextDatum(schema);
3693  nulls[1] = false;
3694  }
3695  else
3696  nulls[1] = true;
3697 
3698  /* object name */
3699  if (objname)
3700  {
3701  values[2] = CStringGetTextDatum(objname);
3702  nulls[2] = false;
3703  }
3704  else
3705  nulls[2] = true;
3706 
3707  /* object identity */
3708  values[3] = CStringGetTextDatum(getObjectIdentity(&address));
3709  nulls[3] = false;
3710 
3711  htup = heap_form_tuple(tupdesc, values, nulls);
3712 
3714 }
3715 
3716 /*
3717  * SQL-level callable function to obtain object type + identity
3718  */
3719 Datum
3721 {
3722  Oid classid = PG_GETARG_OID(0);
3723  Oid objid = PG_GETARG_OID(1);
3724  int32 objsubid = PG_GETARG_INT32(2);
3725  ObjectAddress address;
3726  char *identity;
3727  List *names;
3728  List *args;
3729  Datum values[3];
3730  bool nulls[3];
3731  TupleDesc tupdesc;
3732  HeapTuple htup;
3733 
3734  address.classId = classid;
3735  address.objectId = objid;
3736  address.objectSubId = objsubid;
3737 
3738  /*
3739  * Construct a tuple descriptor for the result row. This must match this
3740  * function's pg_proc entry!
3741  */
3742  tupdesc = CreateTemplateTupleDesc(3, false);
3743  TupleDescInitEntry(tupdesc, (AttrNumber) 1, "type",
3744  TEXTOID, -1, 0);
3745  TupleDescInitEntry(tupdesc, (AttrNumber) 2, "object_names",
3746  TEXTARRAYOID, -1, 0);
3747  TupleDescInitEntry(tupdesc, (AttrNumber) 3, "object_args",
3748  TEXTARRAYOID, -1, 0);
3749 
3750  tupdesc = BlessTupleDesc(tupdesc);
3751 
3752  /* object type */
3753  values[0] = CStringGetTextDatum(getObjectTypeDescription(&address));
3754  nulls[0] = false;
3755 
3756  /* object identity */
3757  identity = getObjectIdentityParts(&address, &names, &args);
3758  pfree(identity);
3759 
3760  /* object_names */
3761  values[1] = PointerGetDatum(strlist_to_textarray(names));
3762  nulls[1] = false;
3763 
3764  /* object_args */
3765  if (args)
3766  values[2] = PointerGetDatum(strlist_to_textarray(args));
3767  else
3769  nulls[2] = false;
3770 
3771  htup = heap_form_tuple(tupdesc, values, nulls);
3772 
3774 }
3775 
3776 /*
3777  * Return a palloc'ed string that describes the type of object that the
3778  * passed address is for.
3779  *
3780  * Keep ObjectTypeMap in sync with this.
3781  */
3782 char *
3784 {
3786 
3787  initStringInfo(&buffer);
3788 
3789  switch (getObjectClass(object))
3790  {
3791  case OCLASS_CLASS:
3792  getRelationTypeDescription(&buffer, object->objectId,
3793  object->objectSubId);
3794  break;
3795 
3796  case OCLASS_PROC:
3797  getProcedureTypeDescription(&buffer, object->objectId);
3798  break;
3799 
3800  case OCLASS_TYPE:
3801  appendStringInfoString(&buffer, "type");
3802  break;
3803 
3804  case OCLASS_CAST:
3805  appendStringInfoString(&buffer, "cast");
3806  break;
3807 
3808  case OCLASS_COLLATION:
3809  appendStringInfoString(&buffer, "collation");
3810  break;
3811 
3812  case OCLASS_CONSTRAINT:
3813  getConstraintTypeDescription(&buffer, object->objectId);
3814  break;
3815 
3816  case OCLASS_CONVERSION:
3817  appendStringInfoString(&buffer, "conversion");
3818  break;
3819 
3820  case OCLASS_DEFAULT:
3821  appendStringInfoString(&buffer, "default value");
3822  break;
3823 
3824  case OCLASS_LANGUAGE:
3825  appendStringInfoString(&buffer, "language");
3826  break;
3827 
3828  case OCLASS_LARGEOBJECT:
3829  appendStringInfoString(&buffer, "large object");
3830  break;
3831 
3832  case OCLASS_OPERATOR:
3833  appendStringInfoString(&buffer, "operator");
3834  break;
3835 
3836  case OCLASS_OPCLASS:
3837  appendStringInfoString(&buffer, "operator class");
3838  break;
3839 
3840  case OCLASS_OPFAMILY:
3841  appendStringInfoString(&buffer, "operator family");
3842  break;
3843 
3844  case OCLASS_AM:
3845  appendStringInfoString(&buffer, "access method");
3846  break;
3847 
3848  case OCLASS_AMOP:
3849  appendStringInfoString(&buffer, "operator of access method");
3850  break;
3851 
3852  case OCLASS_AMPROC:
3853  appendStringInfoString(&buffer, "function of access method");
3854  break;
3855 
3856  case OCLASS_REWRITE:
3857  appendStringInfoString(&buffer, "rule");
3858  break;
3859 
3860  case OCLASS_TRIGGER:
3861  appendStringInfoString(&buffer, "trigger");
3862  break;
3863 
3864  case OCLASS_SCHEMA:
3865  appendStringInfoString(&buffer, "schema");
3866  break;
3867 
3868  case OCLASS_STATISTIC_EXT:
3869  appendStringInfoString(&buffer, "statistics object");
3870  break;
3871 
3872  case OCLASS_TSPARSER:
3873  appendStringInfoString(&buffer, "text search parser");
3874  break;
3875 
3876  case OCLASS_TSDICT:
3877  appendStringInfoString(&buffer, "text search dictionary");
3878  break;
3879 
3880  case OCLASS_TSTEMPLATE:
3881  appendStringInfoString(&buffer, "text search template");
3882  break;
3883 
3884  case OCLASS_TSCONFIG:
3885  appendStringInfoString(&buffer, "text search configuration");
3886  break;
3887 
3888  case OCLASS_ROLE:
3889  appendStringInfoString(&buffer, "role");
3890  break;
3891 
3892  case OCLASS_DATABASE:
3893  appendStringInfoString(&buffer, "database");
3894  break;
3895 
3896  case OCLASS_TBLSPACE:
3897  appendStringInfoString(&buffer, "tablespace");
3898  break;
3899 
3900  case OCLASS_FDW:
3901  appendStringInfoString(&buffer, "foreign-data wrapper");
3902  break;
3903 
3904  case OCLASS_FOREIGN_SERVER:
3905  appendStringInfoString(&buffer, "server");
3906  break;
3907 
3908  case OCLASS_USER_MAPPING:
3909  appendStringInfoString(&buffer, "user mapping");
3910  break;
3911 
3912  case OCLASS_DEFACL:
3913  appendStringInfoString(&buffer, "default acl");
3914  break;
3915 
3916  case OCLASS_EXTENSION:
3917  appendStringInfoString(&buffer, "extension");
3918  break;
3919 
3920  case OCLASS_EVENT_TRIGGER:
3921  appendStringInfoString(&buffer, "event trigger");
3922  break;
3923 
3924  case OCLASS_POLICY:
3925  appendStringInfoString(&buffer, "policy");
3926  break;
3927 
3928  case OCLASS_PUBLICATION:
3929  appendStringInfoString(&buffer, "publication");
3930  break;
3931 
3933  appendStringInfoString(&buffer, "publication relation");
3934  break;
3935 
3936  case OCLASS_SUBSCRIPTION:
3937  appendStringInfoString(&buffer, "subscription");
3938  break;
3939 
3940  case OCLASS_TRANSFORM:
3941  appendStringInfoString(&buffer, "transform");
3942  break;
3943 
3944  /*
3945  * There's intentionally no default: case here; we want the
3946  * compiler to warn if a new OCLASS hasn't been handled above.
3947  */
3948  }
3949 
3950  return buffer.data;
3951 }
3952 
3953 /*
3954  * subroutine for getObjectTypeDescription: describe a relation type
3955  */
3956 static void
3957 getRelationTypeDescription(StringInfo buffer, Oid relid, int32 objectSubId)
3958 {
3959  HeapTuple relTup;
3960  Form_pg_class relForm;
3961 
3962  relTup = SearchSysCache1(RELOID,
3963  ObjectIdGetDatum(relid));
3964  if (!HeapTupleIsValid(relTup))
3965  elog(ERROR, "cache lookup failed for relation %u", relid);
3966  relForm = (Form_pg_class) GETSTRUCT(relTup);
3967 
3968  switch (relForm->relkind)
3969  {
3970  case RELKIND_RELATION:
3972  appendStringInfoString(buffer, "table");
3973  break;
3974  case RELKIND_INDEX:
3976  appendStringInfoString(buffer, "index");
3977  break;
3978  case RELKIND_SEQUENCE:
3979  appendStringInfoString(buffer, "sequence");
3980  break;
3981  case RELKIND_TOASTVALUE:
3982  appendStringInfoString(buffer, "toast table");
3983  break;
3984  case RELKIND_VIEW:
3985  appendStringInfoString(buffer, "view");
3986  break;
3987  case RELKIND_MATVIEW:
3988  appendStringInfoString(buffer, "materialized view");
3989  break;
3991  appendStringInfoString(buffer, "composite type");
3992  break;
3993  case RELKIND_FOREIGN_TABLE:
3994  appendStringInfoString(buffer, "foreign table");
3995  break;
3996  default:
3997  /* shouldn't get here */
3998  appendStringInfoString(buffer, "relation");
3999  break;
4000  }
4001 
4002  if (objectSubId != 0)
4003  appendStringInfoString(buffer, " column");
4004 
4005  ReleaseSysCache(relTup);
4006 }
4007 
4008 /*
4009  * subroutine for getObjectTypeDescription: describe a constraint type
4010  */
4011 static void
4013 {
4014  Relation constrRel;
4015  HeapTuple constrTup;
4016  Form_pg_constraint constrForm;
4017 
4019  constrTup = get_catalog_object_by_oid(constrRel, constroid);
4020  if (!HeapTupleIsValid(constrTup))
4021  elog(ERROR, "cache lookup failed for constraint %u", constroid);
4022 
4023  constrForm = (Form_pg_constraint) GETSTRUCT(constrTup);
4024 
4025  if (OidIsValid(constrForm->conrelid))
4026  appendStringInfoString(buffer, "table constraint");
4027  else if (OidIsValid(constrForm->contypid))
4028  appendStringInfoString(buffer, "domain constraint");
4029  else
4030  elog(ERROR, "invalid constraint %u", HeapTupleGetOid(constrTup));
4031 
4032  heap_close(constrRel, AccessShareLock);
4033 }
4034 
4035 /*
4036  * subroutine for getObjectTypeDescription: describe a procedure type
4037  */
4038 static void
4040 {
4041  HeapTuple procTup;
4042  Form_pg_proc procForm;
4043 
4044  procTup = SearchSysCache1(PROCOID,
4045  ObjectIdGetDatum(procid));
4046  if (!HeapTupleIsValid(procTup))
4047  elog(ERROR, "cache lookup failed for procedure %u", procid);
4048  procForm = (Form_pg_proc) GETSTRUCT(procTup);
4049 
4050  if (procForm->proisagg)
4051  appendStringInfoString(buffer, "aggregate");
4052  else if (procForm->prorettype == InvalidOid)
4053  appendStringInfoString(buffer, "procedure");
4054  else
4055  appendStringInfoString(buffer, "function");
4056 
4057  ReleaseSysCache(procTup);
4058 }
4059 
4060 /*
4061  * Obtain a given object's identity, as a palloc'ed string.
4062  *
4063  * This is for machine consumption, so it's not translated. All elements are
4064  * schema-qualified when appropriate.
4065  */
4066 char *
4068 {
4069  return getObjectIdentityParts(object, NULL, NULL);
4070 }
4071 
4072 /*
4073  * As above, but more detailed.
4074  *
4075  * There are two sets of return values: the identity itself as a palloc'd
4076  * string is returned. objname and objargs, if not NULL, are output parameters
4077  * that receive lists of C-strings that are useful to give back to
4078  * get_object_address() to reconstruct the ObjectAddress.
4079  */
4080 char *
4082  List **objname, List **objargs)
4083 {
4085 
4086  initStringInfo(&buffer);
4087 
4088  /*
4089  * Make sure that both objname and objargs were passed, or none was; and
4090  * initialize them to empty lists. For objname this is useless because it
4091  * will be initialized in all cases inside the switch; but we do it anyway
4092  * so that we can test below that no branch leaves it unset.
4093  */
4094  Assert(PointerIsValid(objname) == PointerIsValid(objargs));
4095  if (objname)
4096  {
4097  *objname = NIL;
4098  *objargs = NIL;
4099  }
4100 
4101  switch (getObjectClass(object))
4102  {
4103  case OCLASS_CLASS:
4104  getRelationIdentity(&buffer, object->objectId, objname);
4105  if (object->objectSubId != 0)
4106  {
4107  char *attr;
4108 
4109  attr = get_attname(object->objectId, object->objectSubId,
4110  false);
4111  appendStringInfo(&buffer, ".%s", quote_identifier(attr));
4112  if (objname)
4113  *objname = lappend(*objname, attr);
4114  }
4115  break;
4116 
4117  case OCLASS_PROC:
4118  appendStringInfoString(&buffer,
4120  if (objname)
4121  format_procedure_parts(object->objectId, objname, objargs);
4122  break;
4123 
4124  case OCLASS_TYPE:
4125  {
4126  char *typeout;
4127 
4128  typeout = format_type_be_qualified(object->objectId);
4129  appendStringInfoString(&buffer, typeout);
4130  if (objname)
4131  *objname = list_make1(typeout);
4132  }
4133  break;
4134 
4135  case OCLASS_CAST:
4136  {
4137  Relation castRel;
4138  HeapTuple tup;
4139  Form_pg_cast castForm;
4140 
4142 
4143  tup = get_catalog_object_by_oid(castRel, object->objectId);
4144 
4145  if (!HeapTupleIsValid(tup))
4146  elog(ERROR, "could not find tuple for cast %u",
4147  object->objectId);
4148 
4149  castForm = (Form_pg_cast) GETSTRUCT(tup);
4150 
4151  appendStringInfo(&buffer, "(%s AS %s)",
4152  format_type_be_qualified(castForm->castsource),
4153  format_type_be_qualified(castForm->casttarget));
4154 
4155  if (objname)
4156  {
4157  *objname = list_make1(format_type_be_qualified(castForm->castsource));
4158  *objargs = list_make1(format_type_be_qualified(castForm->casttarget));
4159  }
4160 
4161  heap_close(castRel, AccessShareLock);
4162  break;
4163  }
4164 
4165  case OCLASS_COLLATION:
4166  {
4167  HeapTuple collTup;
4168  Form_pg_collation coll;
4169  char *schema;
4170 
4171  collTup = SearchSysCache1(COLLOID,
4172  ObjectIdGetDatum(object->objectId));
4173  if (!HeapTupleIsValid(collTup))
4174  elog(ERROR, "cache lookup failed for collation %u",
4175  object->objectId);
4176  coll = (Form_pg_collation) GETSTRUCT(collTup);
4177  schema = get_namespace_name_or_temp(coll->collnamespace);
4178  appendStringInfoString(&buffer,
4180  NameStr(coll->collname)));
4181  if (objname)
4182  *objname = list_make2(schema,
4183  pstrdup(NameStr(coll->collname)));
4184  ReleaseSysCache(collTup);
4185  break;
4186  }
4187 
4188  case OCLASS_CONSTRAINT:
4189  {
4190  HeapTuple conTup;
4191  Form_pg_constraint con;
4192 
4193  conTup = SearchSysCache1(CONSTROID,
4194  ObjectIdGetDatum(object->objectId));
4195  if (!HeapTupleIsValid(conTup))
4196  elog(ERROR, "cache lookup failed for constraint %u",
4197  object->objectId);
4198  con = (Form_pg_constraint) GETSTRUCT(conTup);
4199 
4200  if (OidIsValid(con->conrelid))
4201  {
4202  appendStringInfo(&buffer, "%s on ",
4203  quote_identifier(NameStr(con->conname)));
4204  getRelationIdentity(&buffer, con->conrelid, objname);
4205  if (objname)
4206  *objname = lappend(*objname, pstrdup(NameStr(con->conname)));
4207  }
4208  else
4209  {
4210  ObjectAddress domain;
4211 
4212  Assert(OidIsValid(con->contypid));
4213  domain.classId = TypeRelationId;
4214  domain.objectId = con->contypid;
4215  domain.objectSubId = 0;
4216 
4217  appendStringInfo(&buffer, "%s on %s",
4218  quote_identifier(NameStr(con->conname)),
4219  getObjectIdentityParts(&domain, objname, objargs));
4220 
4221  if (objname)
4222  *objargs = lappend(*objargs, pstrdup(NameStr(con->conname)));
4223  }
4224 
4225  ReleaseSysCache(conTup);
4226  break;
4227  }
4228 
4229  case OCLASS_CONVERSION:
4230  {
4231  HeapTuple conTup;
4232  Form_pg_conversion conForm;
4233  char *schema;
4234 
4235  conTup = SearchSysCache1(CONVOID,
4236  ObjectIdGetDatum(object->objectId));
4237  if (!HeapTupleIsValid(conTup))
4238  elog(ERROR, "cache lookup failed for conversion %u",
4239  object->objectId);
4240  conForm = (Form_pg_conversion) GETSTRUCT(conTup);
4241  schema = get_namespace_name_or_temp(conForm->connamespace);
4242  appendStringInfoString(&buffer,
4244  NameStr(conForm->conname)));
4245  if (objname)
4246  *objname = list_make2(schema,
4247  pstrdup(NameStr(conForm->conname)));
4248  ReleaseSysCache(conTup);
4249  break;
4250  }
4251 
4252  case OCLASS_DEFAULT:
4253  {
4254  Relation attrdefDesc;
4255  ScanKeyData skey[1];
4256  SysScanDesc adscan;
4257 
4258  HeapTuple tup;
4259  Form_pg_attrdef attrdef;
4260  ObjectAddress colobject;
4261 
4263 
4264  ScanKeyInit(&skey[0],
4266  BTEqualStrategyNumber, F_OIDEQ,
4267  ObjectIdGetDatum(object->objectId));
4268 
4269  adscan = systable_beginscan(attrdefDesc, AttrDefaultOidIndexId,
4270  true, NULL, 1, skey);
4271 
4272  tup = systable_getnext(adscan);
4273 
4274  if (!HeapTupleIsValid(tup))
4275  elog(ERROR, "could not find tuple for attrdef %u",
4276  object->objectId);
4277 
4278  attrdef = (Form_pg_attrdef) GETSTRUCT(tup);
4279 
4280  colobject.classId = RelationRelationId;
4281  colobject.objectId = attrdef->adrelid;
4282  colobject.objectSubId = attrdef->adnum;
4283 
4284  appendStringInfo(&buffer, "for %s",
4285  getObjectIdentityParts(&colobject,
4286  objname, objargs));
4287 
4288  systable_endscan(adscan);
4289  heap_close(attrdefDesc, AccessShareLock);
4290  break;
4291  }
4292 
4293  case OCLASS_LANGUAGE:
4294  {
4295  HeapTuple langTup;
4296  Form_pg_language langForm;
4297 
4298  langTup = SearchSysCache1(LANGOID,
4299  ObjectIdGetDatum(object->objectId));
4300  if (!HeapTupleIsValid(langTup))
4301  elog(ERROR, "cache lookup failed for language %u",
4302  object->objectId);
4303  langForm = (Form_pg_language) GETSTRUCT(langTup);
4304  appendStringInfoString(&buffer,
4305  quote_identifier(NameStr(langForm->lanname)));
4306  if (objname)
4307  *objname = list_make1(pstrdup(NameStr(langForm->lanname)));
4308  ReleaseSysCache(langTup);
4309  break;
4310  }
4311  case OCLASS_LARGEOBJECT:
4312  appendStringInfo(&buffer, "%u",
4313  object->objectId);
4314  if (objname)
4315  *objname = list_make1(psprintf("%u", object->objectId));
4316  break;
4317 
4318  case OCLASS_OPERATOR:
4319  appendStringInfoString(&buffer,
4321  if (objname)
4322  format_operator_parts(object->objectId, objname, objargs);
4323  break;
4324 
4325  case OCLASS_OPCLASS:
4326  {
4327  HeapTuple opcTup;
4328  Form_pg_opclass opcForm;
4329  HeapTuple amTup;
4330  Form_pg_am amForm;
4331  char *schema;
4332 
4333  opcTup = SearchSysCache1(CLAOID,
4334  ObjectIdGetDatum(object->objectId));
4335  if (!HeapTupleIsValid(opcTup))
4336  elog(ERROR, "cache lookup failed for opclass %u",
4337  object->objectId);
4338  opcForm = (Form_pg_opclass) GETSTRUCT(opcTup);
4339  schema = get_namespace_name_or_temp(opcForm->opcnamespace);
4340 
4341  amTup = SearchSysCache1(AMOID,
4342  ObjectIdGetDatum(opcForm->opcmethod));
4343  if (!HeapTupleIsValid(amTup))
4344  elog(ERROR, "cache lookup failed for access method %u",
4345  opcForm->opcmethod);
4346  amForm = (Form_pg_am) GETSTRUCT(amTup);
4347 
4348  appendStringInfo(&buffer, "%s USING %s",
4350  NameStr(opcForm->opcname)),
4351  quote_identifier(NameStr(amForm->amname)));
4352  if (objname)
4353  *objname = list_make3(pstrdup(NameStr(amForm->amname)),
4354  schema,
4355  pstrdup(NameStr(opcForm->opcname)));
4356 
4357  ReleaseSysCache(amTup);
4358  ReleaseSysCache(opcTup);
4359  break;
4360  }
4361 
4362  case OCLASS_OPFAMILY:
4363  getOpFamilyIdentity(&buffer, object->objectId, objname);
4364  break;
4365 
4366  case OCLASS_AM:
4367  {
4368  char *amname;
4369 
4370  amname = get_am_name(object->objectId);
4371  if (!amname)
4372  elog(ERROR, "cache lookup failed for access method %u",
4373  object->objectId);
4374  appendStringInfoString(&buffer, quote_identifier(amname));
4375  if (objname)
4376  *objname = list_make1(amname);
4377  }
4378  break;
4379 
4380  case OCLASS_AMOP:
4381  {
4382  Relation amopDesc;
4383  HeapTuple tup;
4384  ScanKeyData skey[1];
4385  SysScanDesc amscan;
4386  Form_pg_amop amopForm;
4387  StringInfoData opfam;
4388  char *ltype;
4389  char *rtype;
4390 
4392  AccessShareLock);
4393 
4394  ScanKeyInit(&skey[0],
4396  BTEqualStrategyNumber, F_OIDEQ,
4397  ObjectIdGetDatum(object->objectId));
4398 
4399  amscan = systable_beginscan(amopDesc, AccessMethodOperatorOidIndexId, true,
4400  NULL, 1, skey);
4401 
4402  tup = systable_getnext(amscan);
4403 
4404  if (!HeapTupleIsValid(tup))
4405  elog(ERROR, "could not find tuple for amop entry %u",
4406  object->objectId);
4407 
4408  amopForm = (Form_pg_amop) GETSTRUCT(tup);
4409 
4410  initStringInfo(&opfam);
4411  getOpFamilyIdentity(&opfam, amopForm->amopfamily, objname);
4412 
4413  ltype = format_type_be_qualified(amopForm->amoplefttype);
4414  rtype = format_type_be_qualified(amopForm->amoprighttype);
4415 
4416  if (objname)
4417  {
4418  *objname = lappend(*objname,
4419  psprintf("%d", amopForm->amopstrategy));
4420  *objargs = list_make2(ltype, rtype);
4421  }
4422 
4423  appendStringInfo(&buffer, "operator %d (%s, %s) of %s",
4424  amopForm->amopstrategy,
4425  ltype, rtype, opfam.data);
4426 
4427  pfree(opfam.data);
4428 
4429  systable_endscan(amscan);
4430  heap_close(amopDesc, AccessShareLock);
4431  break;
4432  }
4433 
4434  case OCLASS_AMPROC:
4435  {
4436  Relation amprocDesc;
4437  ScanKeyData skey[1];
4438  SysScanDesc amscan;
4439  HeapTuple tup;
4440  Form_pg_amproc amprocForm;
4441  StringInfoData opfam;
4442  char *ltype;
4443  char *rtype;
4444 
4446  AccessShareLock);
4447 
4448  ScanKeyInit(&skey[0],
4450  BTEqualStrategyNumber, F_OIDEQ,
4451  ObjectIdGetDatum(object->objectId));
4452 
4453  amscan = systable_beginscan(amprocDesc, AccessMethodProcedureOidIndexId, true,
4454  NULL, 1, skey);
4455 
4456  tup = systable_getnext(amscan);
4457 
4458  if (!HeapTupleIsValid(tup))
4459  elog(ERROR, "could not find tuple for amproc entry %u",
4460  object->objectId);
4461 
4462  amprocForm = (Form_pg_amproc) GETSTRUCT(tup);
4463 
4464  initStringInfo(&opfam);
4465  getOpFamilyIdentity(&opfam, amprocForm->amprocfamily, objname);
4466 
4467  ltype = format_type_be_qualified(amprocForm->amproclefttype);
4468  rtype = format_type_be_qualified(amprocForm->amprocrighttype);
4469 
4470  if (objname)
4471  {
4472  *objname = lappend(*objname,
4473  psprintf("%d", amprocForm->amprocnum));
4474  *objargs = list_make2(ltype, rtype);
4475  }
4476 
4477  appendStringInfo(&buffer, "function %d (%s, %s) of %s",
4478  amprocForm->amprocnum,
4479  ltype, rtype, opfam.data);
4480 
4481  pfree(opfam.data);
4482 
4483  systable_endscan(amscan);
4484  heap_close(amprocDesc, AccessShareLock);
4485  break;
4486  }
4487 
4488  case OCLASS_REWRITE:
4489  {
4490  Relation ruleDesc;
4491  HeapTuple tup;
4493 
4495 
4496  tup = get_catalog_object_by_oid(ruleDesc, object->objectId);
4497 
4498  if (!HeapTupleIsValid(tup))
4499  elog(ERROR, "could not find tuple for rule %u",
4500  object->objectId);
4501 
4502  rule = (Form_pg_rewrite) GETSTRUCT(tup);
4503 
4504  appendStringInfo(&buffer, "%s on ",
4505  quote_identifier(NameStr(rule->rulename)));
4506  getRelationIdentity(&buffer, rule->ev_class, objname);
4507  if (objname)
4508  *objname = lappend(*objname, pstrdup(NameStr(rule->rulename)));
4509 
4510  heap_close(ruleDesc, AccessShareLock);
4511  break;
4512  }
4513 
4514  case OCLASS_TRIGGER:
4515  {
4516  Relation trigDesc;
4517  HeapTuple tup;
4518  Form_pg_trigger trig;
4519 
4521 
4522  tup = get_catalog_object_by_oid(trigDesc, object->objectId);
4523 
4524  if (!HeapTupleIsValid(tup))
4525  elog(ERROR, "could not find tuple for trigger %u",
4526  object->objectId);
4527 
4528  trig = (Form_pg_trigger) GETSTRUCT(tup);
4529 
4530  appendStringInfo(&buffer, "%s on ",
4531  quote_identifier(NameStr(trig->tgname)));
4532  getRelationIdentity(&buffer, trig->tgrelid, objname);
4533  if (objname)
4534  *objname = lappend(*objname, pstrdup(NameStr(trig->tgname)));
4535 
4536  heap_close(trigDesc, AccessShareLock);
4537  break;
4538  }
4539 
4540  case OCLASS_SCHEMA:
4541  {
4542  char *nspname;
4543 
4544  nspname = get_namespace_name_or_temp(object->objectId);
4545  if (!nspname)
4546  elog(ERROR, "cache lookup failed for namespace %u",
4547  object->objectId);
4548  appendStringInfoString(&buffer,
4549  quote_identifier(nspname));
4550  if (objname)
4551  *objname = list_make1(nspname);
4552  break;
4553  }
4554 
4555  case OCLASS_STATISTIC_EXT:
4556  {
4557  HeapTuple tup;
4558  Form_pg_statistic_ext formStatistic;
4559  char *schema;
4560 
4562  ObjectIdGetDatum(object->objectId));
4563  if (!HeapTupleIsValid(tup))
4564  elog(ERROR, "cache lookup failed for statistics object %u",
4565  object->objectId);
4566  formStatistic = (Form_pg_statistic_ext) GETSTRUCT(tup);
4567  schema = get_namespace_name_or_temp(formStatistic->stxnamespace);
4568  appendStringInfoString(&buffer,
4570  NameStr(formStatistic->stxname)));
4571  if (objname)
4572  *objname = list_make2(schema,
4573  pstrdup(NameStr(formStatistic->stxname)));
4574  ReleaseSysCache(tup);
4575  }
4576  break;
4577 
4578  case OCLASS_TSPARSER:
4579  {
4580  HeapTuple tup;
4581  Form_pg_ts_parser formParser;
4582  char *schema;
4583 
4585  ObjectIdGetDatum(object->objectId));
4586  if (!HeapTupleIsValid(tup))
4587  elog(ERROR, "cache lookup failed for text search parser %u",
4588  object->objectId);
4589  formParser = (Form_pg_ts_parser) GETSTRUCT(tup);
4590  schema = get_namespace_name_or_temp(formParser->prsnamespace);
4591  appendStringInfoString(&buffer,
4593  NameStr(formParser->prsname)));
4594  if (objname)
4595  *objname = list_make2(schema,
4596  pstrdup(NameStr(formParser->prsname)));
4597  ReleaseSysCache(tup);
4598  break;
4599  }
4600 
4601  case OCLASS_TSDICT:
4602  {
4603  HeapTuple tup;
4604  Form_pg_ts_dict formDict;
4605  char *schema;
4606 
4607  tup = SearchSysCache1(TSDICTOID,
4608  ObjectIdGetDatum(object->objectId));
4609  if (!HeapTupleIsValid(tup))
4610  elog(ERROR, "cache lookup failed for text search dictionary %u",
4611  object->objectId);
4612  formDict = (Form_pg_ts_dict) GETSTRUCT(tup);
4613  schema = get_namespace_name_or_temp(formDict->dictnamespace);
4614  appendStringInfoString(&buffer,
4616  NameStr(formDict->dictname)));
4617  if (objname)
4618  *objname = list_make2(schema,
4619  pstrdup(NameStr(formDict->dictname)));
4620  ReleaseSysCache(tup);
4621  break;
4622  }
4623 
4624  case OCLASS_TSTEMPLATE:
4625  {
4626  HeapTuple tup;
4627  Form_pg_ts_template formTmpl;
4628  char *schema;
4629 
4631  ObjectIdGetDatum(object->objectId));
4632  if (!HeapTupleIsValid(tup))
4633  elog(ERROR, "cache lookup failed for text search template %u",
4634  object->objectId);
4635  formTmpl = (Form_pg_ts_template) GETSTRUCT(tup);
4636  schema = get_namespace_name_or_temp(formTmpl->tmplnamespace);
4637  appendStringInfoString(&buffer,
4639  NameStr(formTmpl->tmplname)));
4640  if (objname)
4641  *objname = list_make2(schema,
4642  pstrdup(NameStr(formTmpl->tmplname)));
4643  ReleaseSysCache(tup);
4644  break;
4645  }
4646 
4647  case OCLASS_TSCONFIG:
4648  {
4649  HeapTuple tup;
4650  Form_pg_ts_config formCfg;
4651  char *schema;
4652 
4654  ObjectIdGetDatum(object->objectId));
4655  if (!HeapTupleIsValid(tup))
4656  elog(ERROR, "cache lookup failed for text search configuration %u",
4657  object->objectId);
4658  formCfg = (Form_pg_ts_config) GETSTRUCT(tup);
4659  schema = get_namespace_name_or_temp(formCfg->cfgnamespace);
4660  appendStringInfoString(&buffer,
4662  NameStr(formCfg->cfgname)));
4663  if (objname)
4664  *objname = list_make2(schema,
4665  pstrdup(NameStr(formCfg->cfgname)));
4666  ReleaseSysCache(tup);
4667  break;
4668  }
4669 
4670  case OCLASS_ROLE:
4671  {
4672  char *username;
4673 
4674  username = GetUserNameFromId(object->objectId, false);
4675  if (objname)
4676  *objname = list_make1(username);
4677  appendStringInfoString(&buffer,
4678  quote_identifier(username));
4679  break;
4680  }
4681 
4682  case OCLASS_DATABASE:
4683  {
4684  char *datname;
4685 
4686  datname = get_database_name(object->objectId);
4687  if (!datname)
4688  elog(ERROR, "cache lookup failed for database %u",
4689  object->objectId);
4690  if (objname)
4691  *objname = list_make1(datname);
4692  appendStringInfoString(&buffer,
4693  quote_identifier(datname));
4694  break;
4695  }
4696 
4697  case OCLASS_TBLSPACE:
4698  {
4699  char *tblspace;
4700 
4701  tblspace = get_tablespace_name(object->objectId);
4702  if (!tblspace)
4703  elog(ERROR, "cache lookup failed for tablespace %u",
4704  object->objectId);
4705  if (objname)
4706  *objname = list_make1(tblspace);
4707  appendStringInfoString(&buffer,
4708  quote_identifier(tblspace));
4709  break;
4710  }
4711 
4712  case OCLASS_FDW:
4713  {
4714  ForeignDataWrapper *fdw;
4715 
4716  fdw = GetForeignDataWrapper(object->objectId);
4718  if (objname)
4719  *objname = list_make1(pstrdup(fdw->fdwname));
4720  break;
4721  }
4722 
4723  case OCLASS_FOREIGN_SERVER:
4724  {
4725  ForeignServer *srv;
4726 
4727  srv = GetForeignServer(object->objectId);
4728  appendStringInfoString(&buffer,
4730  if (objname)
4731  *objname = list_make1(pstrdup(srv->servername));
4732  break;
4733  }
4734 
4735  case OCLASS_USER_MAPPING:
4736  {
4737  HeapTuple tup;
4738  Oid useid;
4739  Form_pg_user_mapping umform;
4740  ForeignServer *srv;
4741  const char *usename;
4742 
4744  ObjectIdGetDatum(object->objectId));
4745  if (!HeapTupleIsValid(tup))
4746  elog(ERROR, "cache lookup failed for user mapping %u",
4747  object->objectId);
4748  umform = (Form_pg_user_mapping) GETSTRUCT(tup);
4749  useid = umform->umuser;
4750  srv = GetForeignServer(umform->umserver);
4751 
4752  ReleaseSysCache(tup);
4753 
4754  if (OidIsValid(useid))
4755  usename = GetUserNameFromId(useid, false);
4756  else
4757  usename = "public";
4758 
4759  if (objname)
4760  {
4761  *objname = list_make1(pstrdup(usename));
4762  *objargs = list_make1(pstrdup(srv->servername));
4763  }
4764 
4765  appendStringInfo(&buffer, "%s on server %s",
4766  quote_identifier(usename),
4767  srv->servername);
4768  break;
4769  }
4770 
4771  case OCLASS_DEFACL:
4772  {
4773  Relation defaclrel;
4774  ScanKeyData skey[1];
4775  SysScanDesc rcscan;
4776  HeapTuple tup;
4777  Form_pg_default_acl defacl;
4778  char *schema;
4779  char *username;
4780 
4782 
4783  ScanKeyInit(&skey[0],
4785  BTEqualStrategyNumber, F_OIDEQ,
4786  ObjectIdGetDatum(object->objectId));
4787 
4788  rcscan = systable_beginscan(defaclrel, DefaultAclOidIndexId,
4789  true, NULL, 1, skey);
4790 
4791  tup = systable_getnext(rcscan);
4792 
4793  if (!HeapTupleIsValid(tup))
4794  elog(ERROR, "could not find tuple for default ACL %u",
4795  object->objectId);
4796 
4797  defacl = (Form_pg_default_acl) GETSTRUCT(tup);
4798 
4799  username = GetUserNameFromId(defacl->defaclrole, false);
4800  appendStringInfo(&buffer,
4801  "for role %s",
4802  quote_identifier(username));
4803 
4804  if (OidIsValid(defacl->defaclnamespace))
4805  {
4806  schema = get_namespace_name_or_temp(defacl->defaclnamespace);
4807  appendStringInfo(&buffer,
4808  " in schema %s",
4809  quote_identifier(schema));
4810  }
4811  else
4812  schema = NULL;
4813 
4814  switch (defacl->defaclobjtype)
4815  {
4816  case DEFACLOBJ_RELATION:
4817  appendStringInfoString(&buffer,
4818  " on tables");
4819  break;
4820  case DEFACLOBJ_SEQUENCE:
4821  appendStringInfoString(&buffer,
4822  " on sequences");
4823  break;
4824  case DEFACLOBJ_FUNCTION:
4825  appendStringInfoString(&buffer,
4826  " on functions");
4827  break;
4828  case DEFACLOBJ_TYPE:
4829  appendStringInfoString(&buffer,
4830  " on types");
4831  break;
4832  case DEFACLOBJ_NAMESPACE:
4833  appendStringInfoString(&buffer,
4834  " on schemas");
4835  break;
4836  }
4837 
4838  if (objname)
4839  {
4840  *objname = list_make1(username);
4841  if (schema)
4842  *objname = lappend(*objname, schema);
4843  *objargs = list_make1(psprintf("%c", defacl->defaclobjtype));
4844  }
4845 
4846  systable_endscan(rcscan);
4847  heap_close(defaclrel, AccessShareLock);
4848  break;
4849  }
4850 
4851  case OCLASS_EXTENSION:
4852  {
4853  char *extname;
4854 
4855  extname = get_extension_name(object->objectId);
4856  if (!extname)
4857  elog(ERROR, "cache lookup failed for extension %u",
4858  object->objectId);
4859  appendStringInfoString(&buffer, quote_identifier(extname));
4860  if (objname)
4861  *objname = list_make1(extname);
4862  break;
4863  }
4864 
4865  case OCLASS_EVENT_TRIGGER:
4866  {
4867  HeapTuple tup;
4868  Form_pg_event_trigger trigForm;
4869 
4870  /* no objname support here */
4871  if (objname)
4872  *objname = NIL;
4873 
4875  ObjectIdGetDatum(object->objectId));
4876  if (!HeapTupleIsValid(tup))
4877  elog(ERROR, "cache lookup failed for event trigger %u",
4878  object->objectId);
4879  trigForm = (Form_pg_event_trigger) GETSTRUCT(tup);
4880  appendStringInfoString(&buffer,
4881  quote_identifier(NameStr(trigForm->evtname)));
4882  ReleaseSysCache(tup);
4883  break;
4884  }
4885 
4886  case OCLASS_POLICY:
4887  {
4888  Relation polDesc;
4889  HeapTuple tup;
4890  Form_pg_policy policy;
4891 
4893 
4894  tup = get_catalog_object_by_oid(polDesc, object->objectId);
4895 
4896  if (!HeapTupleIsValid(tup))
4897  elog(ERROR, "could not find tuple for policy %u",
4898  object->objectId);
4899 
4900  policy = (Form_pg_policy) GETSTRUCT(tup);
4901 
4902  appendStringInfo(&buffer, "%s on ",
4903  quote_identifier(NameStr(policy->polname)));
4904  getRelationIdentity(&buffer, policy->polrelid, objname);
4905  if (objname)
4906  *objname = lappend(*objname, pstrdup(NameStr(policy->polname)));
4907 
4908  heap_close(polDesc, AccessShareLock);
4909  break;
4910  }
4911 
4912  case OCLASS_PUBLICATION:
4913  {
4914  char *pubname;
4915 
4916  pubname = get_publication_name(object->objectId);
4917  appendStringInfoString(&buffer,
4918  quote_identifier(pubname));
4919  if (objname)
4920  *objname = list_make1(pubname);
4921  break;
4922  }
4923 
4925  {
4926  HeapTuple tup;
4927  char *pubname;
4928  Form_pg_publication_rel prform;
4929 
4931  ObjectIdGetDatum(object->objectId));
4932  if (!HeapTupleIsValid(tup))
4933  elog(ERROR, "cache lookup failed for publication table %u",
4934  object->objectId);
4935 
4936  prform = (Form_pg_publication_rel) GETSTRUCT(tup);
4937  pubname = get_publication_name(prform->prpubid);
4938 
4939  appendStringInfo(&buffer, _("%s in publication %s"),
4940  get_rel_name(prform->prrelid), pubname);
4941 
4942  if (objname)
4943  {
4944  getRelationIdentity(&buffer, prform->prrelid, objname);
4945  *objargs = list_make1(pubname);
4946  }
4947 
4948  ReleaseSysCache(tup);
4949  break;
4950  }
4951 
4952  case OCLASS_SUBSCRIPTION:
4953  {
4954  char *subname;
4955 
4956  subname = get_subscription_name(object->objectId);
4957  appendStringInfoString(&buffer,
4958  quote_identifier(subname));
4959  if (objname)
4960  *objname = list_make1(subname);
4961  break;
4962  }
4963 
4964  case OCLASS_TRANSFORM:
4965  {
4966  Relation transformDesc;
4967  HeapTuple tup;
4968  Form_pg_transform transform;
4969  char *transformLang;
4970  char *transformType;
4971 
4972  transformDesc = heap_open(TransformRelationId, AccessShareLock);
4973 
4974  tup = get_catalog_object_by_oid(transformDesc, object->objectId);
4975 
4976  if (!HeapTupleIsValid(tup))
4977  elog(ERROR, "could not find tuple for transform %u",
4978  object->objectId);
4979 
4980  transform = (Form_pg_transform) GETSTRUCT(tup);
4981 
4982  transformType = format_type_be_qualified(transform->trftype);
4983  transformLang = get_language_name(transform->trflang, false);
4984 
4985  appendStringInfo(&buffer, "for %s on language %s",
4986  transformType,
4987  transformLang);
4988  if (objname)
4989  {
4990  *objname = list_make1(transformType);
4991  *objargs = list_make1(pstrdup(transformLang));
4992  }
4993 
4994  heap_close(transformDesc, AccessShareLock);
4995  }
4996  break;
4997 
4998  /*
4999  * There's intentionally no default: case here; we want the
5000  * compiler to warn if a new OCLASS hasn't been handled above.
5001  */
5002  }
5003 
5004  /*
5005  * If a get_object_address representation was requested, make sure we are
5006  * providing one. We don't check objargs, because many of the cases above
5007  * leave it as NIL.
5008  */
5009  if (objname && *objname == NIL)
5010  elog(ERROR, "requested object address for unsupported object class %d: text result \"%s\"",
5011  (int) getObjectClass(object), buffer.data);
5012 
5013  return buffer.data;
5014 }
5015 
5016 static void
5017 getOpFamilyIdentity(StringInfo buffer, Oid opfid, List **object)
5018 {
5019  HeapTuple opfTup;
5020  Form_pg_opfamily opfForm;
5021  HeapTuple amTup;
5022  Form_pg_am amForm;
5023  char *schema;
5024 
5025  opfTup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfid));
5026  if (!HeapTupleIsValid(opfTup))
5027  elog(ERROR, "cache lookup failed for opfamily %u", opfid);
5028  opfForm = (Form_pg_opfamily) GETSTRUCT(opfTup);
5029 
5030  amTup = SearchSysCache1(AMOID, ObjectIdGetDatum(opfForm->opfmethod));
5031  if (!HeapTupleIsValid(amTup))
5032  elog(ERROR, "cache lookup failed for access method %u",
5033  opfForm->opfmethod);
5034  amForm = (Form_pg_am) GETSTRUCT(amTup);
5035 
5036  schema = get_namespace_name_or_temp(opfForm->opfnamespace);
5037  appendStringInfo(buffer, "%s USING %s",
5039  NameStr(opfForm->opfname)),
5040  NameStr(amForm->amname));
5041 
5042  if (object)
5043  *object = list_make3(pstrdup(NameStr(amForm->amname)),
5044  pstrdup(schema),
5045  pstrdup(NameStr(opfForm->opfname)));
5046 
5047  ReleaseSysCache(amTup);
5048  ReleaseSysCache(opfTup);
5049 }
5050 
5051 /*
5052  * Append the relation identity (quoted qualified name) to the given
5053  * StringInfo.
5054  */
5055 static void
5056 getRelationIdentity(StringInfo buffer, Oid relid, List **object)
5057 {
5058  HeapTuple relTup;
5059  Form_pg_class relForm;
5060  char *schema;
5061 
5062  relTup = SearchSysCache1(RELOID,
5063  ObjectIdGetDatum(relid));
5064  if (!HeapTupleIsValid(relTup))
5065  elog(ERROR, "cache lookup failed for relation %u", relid);
5066  relForm = (Form_pg_class) GETSTRUCT(relTup);
5067 
5068  schema = get_namespace_name_or_temp(relForm->relnamespace);
5069  appendStringInfoString(buffer,
5071  NameStr(relForm->relname)));
5072  if (object)
5073  *object = list_make2(schema, pstrdup(NameStr(relForm->relname)));
5074 
5075  ReleaseSysCache(relTup);
5076 }
5077 
5078 /*
5079  * Auxiliary function to build a TEXT array out of a list of C-strings.
5080  */
5081 ArrayType *
5083 {
5084  ArrayType *arr;
5085  Datum *datums;
5086  int j = 0;
5087  ListCell *cell;
5088  MemoryContext memcxt;
5089  MemoryContext oldcxt;
5090 
5091  /* Work in a temp context; easier than individually pfree'ing the Datums */
5093  "strlist to array",
5095  oldcxt = MemoryContextSwitchTo(memcxt);
5096 
5097  datums = (Datum *) palloc(sizeof(Datum) * list_length(list));
5098 
5099  foreach(cell, list)
5100  {
5101  char *name = lfirst(cell);
5102 
5103  datums[j++] = CStringGetTextDatum(name);
5104  }
5105 
5106  MemoryContextSwitchTo(oldcxt);
5107 
5108  arr = construct_array(datums, list_length(list),
5109  TEXTOID, -1, false, 'i');
5110 
5111  MemoryContextDelete(memcxt);
5112 
5113  return arr;
5114 }
5115 
5116 ObjectType
5117 get_relkind_objtype(char relkind)
5118 {
5119  switch (relkind)
5120  {
5121  case RELKIND_RELATION:
5123  return OBJECT_TABLE;
5124  case RELKIND_INDEX:
5125  return OBJECT_INDEX;
5126  case RELKIND_SEQUENCE:
5127  return OBJECT_SEQUENCE;
5128  case RELKIND_VIEW:
5129  return OBJECT_VIEW;
5130  case RELKIND_MATVIEW:
5131  return OBJECT_MATVIEW;
5132  case RELKIND_FOREIGN_TABLE:
5133  return OBJECT_FOREIGN_TABLE;
5134  /* other relkinds are not supported here because they don't map to OBJECT_* values */
5135  default:
5136  elog(ERROR, "unexpected relkind: %d", relkind);
5137  return 0;
5138  }
5139 }
#define list_make2(x1, x2)
Definition: pg_list.h:140
bool has_createrole_privilege(Oid roleid)
Definition: aclchk.c:5377
bool pg_collation_ownercheck(Oid coll_oid, Oid roleid)
Definition: aclchk.c:5196
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:4885
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:10435
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:1003
#define TransformRelationId
Definition: pg_transform.h:25
bool pg_ts_dict_ownercheck(Oid dict_oid, Oid roleid)
Definition: aclchk.c:5035
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:4856
#define castNode(_type_, nodeptr)
Definition: nodes.h:582
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:539
#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:5062
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
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1805
#define DatumGetObjectId(X)
Definition: postgres.h:483
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:5116
#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:434
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