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