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