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