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