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 30932 : get_object_address(ObjectType objtype, Node *object,
924 : Relation *relp, LOCKMODE lockmode, bool missing_ok)
925 : {
926 30932 : ObjectAddress address = {InvalidOid, InvalidOid, 0};
927 30932 : ObjectAddress old_address = {InvalidOid, InvalidOid, 0};
928 30932 : 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 31260 : inval_count = SharedInvalidMessageCounter;
942 :
943 : /* Look up object address. */
944 31260 : switch (objtype)
945 : {
946 608 : 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 608 : get_relation_by_qualified_name(objtype, castNode(List, object),
954 : &relation, lockmode,
955 : missing_ok);
956 366 : break;
957 302 : case OBJECT_ATTRIBUTE:
958 : case OBJECT_COLUMN:
959 : address =
960 302 : get_object_address_attribute(objtype, castNode(List, object),
961 : &relation, lockmode,
962 : missing_ok);
963 210 : 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 1632 : case OBJECT_RULE:
971 : case OBJECT_TRIGGER:
972 : case OBJECT_TABCONSTRAINT:
973 : case OBJECT_POLICY:
974 1632 : address = get_object_address_relobject(objtype, castNode(List, object),
975 : &relation, missing_ok);
976 1392 : break;
977 62 : case OBJECT_DOMCONSTRAINT:
978 : {
979 : List *objlist;
980 : ObjectAddress domaddr;
981 : char *constrname;
982 :
983 62 : objlist = castNode(List, object);
984 124 : domaddr = get_object_address_type(OBJECT_DOMAIN,
985 62 : linitial_node(TypeName, objlist),
986 : missing_ok);
987 50 : constrname = strVal(lsecond(objlist));
988 :
989 50 : address.classId = ConstraintRelationId;
990 50 : address.objectId = get_domain_constraint_oid(domaddr.objectId,
991 : constrname, missing_ok);
992 44 : address.objectSubId = 0;
993 : }
994 44 : break;
995 4000 : 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 4000 : address = get_object_address_unqualified(objtype,
1009 : castNode(String, object), missing_ok);
1010 3866 : break;
1011 1706 : case OBJECT_TYPE:
1012 : case OBJECT_DOMAIN:
1013 1706 : address = get_object_address_type(objtype, castNode(TypeName, object), missing_ok);
1014 1634 : break;
1015 14880 : case OBJECT_AGGREGATE:
1016 : case OBJECT_FUNCTION:
1017 : case OBJECT_PROCEDURE:
1018 : case OBJECT_ROUTINE:
1019 14880 : address.classId = ProcedureRelationId;
1020 14880 : address.objectId = LookupFuncWithArgs(objtype, castNode(ObjectWithArgs, object), missing_ok);
1021 14588 : address.objectSubId = 0;
1022 14588 : break;
1023 364 : case OBJECT_OPERATOR:
1024 364 : address.classId = OperatorRelationId;
1025 364 : address.objectId = LookupOperWithArgs(castNode(ObjectWithArgs, object), missing_ok);
1026 304 : address.objectSubId = 0;
1027 304 : break;
1028 162 : case OBJECT_COLLATION:
1029 162 : address.classId = CollationRelationId;
1030 162 : address.objectId = get_collation_oid(castNode(List, object), missing_ok);
1031 150 : address.objectSubId = 0;
1032 150 : break;
1033 180 : case OBJECT_CONVERSION:
1034 180 : address.classId = ConversionRelationId;
1035 180 : address.objectId = get_conversion_oid(castNode(List, object), missing_ok);
1036 132 : address.objectSubId = 0;
1037 132 : break;
1038 472 : case OBJECT_OPCLASS:
1039 : case OBJECT_OPFAMILY:
1040 472 : address = get_object_address_opcf(objtype, castNode(List, object), missing_ok);
1041 388 : 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 148 : case OBJECT_LARGEOBJECT:
1047 148 : address.classId = LargeObjectRelationId;
1048 148 : address.objectId = oidparse(object);
1049 142 : address.objectSubId = 0;
1050 142 : 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 124 : break;
1059 82 : case OBJECT_CAST:
1060 : {
1061 82 : TypeName *sourcetype = linitial_node(TypeName, castNode(List, object));
1062 82 : TypeName *targettype = lsecond_node(TypeName, castNode(List, object));
1063 : Oid sourcetypeid;
1064 : Oid targettypeid;
1065 :
1066 82 : sourcetypeid = LookupTypeNameOid(NULL, sourcetype, missing_ok);
1067 76 : targettypeid = LookupTypeNameOid(NULL, targettype, missing_ok);
1068 76 : address.classId = CastRelationId;
1069 70 : address.objectId =
1070 76 : get_cast_oid(sourcetypeid, targettypeid, missing_ok);
1071 70 : address.objectSubId = 0;
1072 : }
1073 70 : 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 100 : case OBJECT_TSPARSER:
1088 100 : address.classId = TSParserRelationId;
1089 100 : address.objectId = get_ts_parser_oid(castNode(List, object), missing_ok);
1090 58 : address.objectSubId = 0;
1091 58 : break;
1092 2920 : case OBJECT_TSDICTIONARY:
1093 2920 : address.classId = TSDictionaryRelationId;
1094 2920 : address.objectId = get_ts_dict_oid(castNode(List, object), missing_ok);
1095 2878 : address.objectSubId = 0;
1096 2878 : break;
1097 196 : case OBJECT_TSTEMPLATE:
1098 196 : address.classId = TSTemplateRelationId;
1099 196 : address.objectId = get_ts_template_oid(castNode(List, object), missing_ok);
1100 154 : address.objectSubId = 0;
1101 154 : break;
1102 2898 : case OBJECT_TSCONFIGURATION:
1103 2898 : address.classId = TSConfigRelationId;
1104 2898 : address.objectId = get_ts_config_oid(castNode(List, object), missing_ok);
1105 2856 : address.objectSubId = 0;
1106 2856 : 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 294 : case OBJECT_STATISTIC_EXT:
1125 294 : address.classId = StatisticExtRelationId;
1126 294 : address.objectId = get_statistics_object_oid(castNode(List, object),
1127 : missing_ok);
1128 294 : address.objectSubId = 0;
1129 294 : break;
1130 : /* no default, to let compiler warn about missing case */
1131 : }
1132 :
1133 29644 : 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 29644 : 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 29260 : if (OidIsValid(old_address.classId))
1151 : {
1152 328 : if (old_address.classId == address.classId
1153 328 : && old_address.objectId == address.objectId
1154 328 : && old_address.objectSubId == address.objectSubId)
1155 328 : 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 28932 : if (address.classId != RelationRelationId)
1174 : {
1175 28356 : if (IsSharedRelation(address.classId))
1176 686 : LockSharedObject(address.classId, address.objectId, 0,
1177 : lockmode);
1178 : else
1179 27670 : 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 28932 : if (inval_count == SharedInvalidMessageCounter || relation != NULL)
1204 : break;
1205 328 : 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 28932 : if (relp)
1213 16360 : *relp = relation;
1214 28932 : 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 4000 : get_object_address_unqualified(ObjectType objtype,
1248 : String *strval, bool missing_ok)
1249 : {
1250 : const char *name;
1251 : ObjectAddress address;
1252 :
1253 4000 : name = strVal(strval);
1254 :
1255 : /* Translate name to OID. */
1256 4000 : 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 582 : case OBJECT_DATABASE:
1264 582 : address.classId = DatabaseRelationId;
1265 582 : address.objectId = get_database_oid(name, missing_ok);
1266 576 : address.objectSubId = 0;
1267 576 : break;
1268 438 : case OBJECT_EXTENSION:
1269 438 : address.classId = ExtensionRelationId;
1270 438 : address.objectId = get_extension_oid(name, missing_ok);
1271 426 : address.objectSubId = 0;
1272 426 : break;
1273 20 : case OBJECT_TABLESPACE:
1274 20 : address.classId = TableSpaceRelationId;
1275 20 : address.objectId = get_tablespace_oid(name, missing_ok);
1276 14 : address.objectSubId = 0;
1277 14 : 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 1124 : case OBJECT_SCHEMA:
1284 1124 : address.classId = NamespaceRelationId;
1285 1124 : address.objectId = get_namespace_oid(name, missing_ok);
1286 1106 : address.objectSubId = 0;
1287 1106 : break;
1288 374 : case OBJECT_LANGUAGE:
1289 374 : address.classId = LanguageRelationId;
1290 374 : address.objectId = get_language_oid(name, missing_ok);
1291 362 : address.objectSubId = 0;
1292 362 : break;
1293 302 : case OBJECT_FDW:
1294 302 : address.classId = ForeignDataWrapperRelationId;
1295 302 : address.objectId = get_foreign_data_wrapper_oid(name, missing_ok);
1296 284 : address.objectSubId = 0;
1297 284 : break;
1298 268 : case OBJECT_FOREIGN_SERVER:
1299 268 : address.classId = ForeignServerRelationId;
1300 268 : address.objectId = get_foreign_server_oid(name, missing_ok);
1301 250 : address.objectSubId = 0;
1302 250 : 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 544 : case OBJECT_PUBLICATION:
1314 544 : address.classId = PublicationRelationId;
1315 544 : address.objectId = get_publication_oid(name, missing_ok);
1316 538 : address.objectSubId = 0;
1317 538 : break;
1318 66 : case OBJECT_SUBSCRIPTION:
1319 66 : address.classId = SubscriptionRelationId;
1320 66 : address.objectId = get_subscription_oid(name, missing_ok);
1321 60 : address.objectSubId = 0;
1322 60 : 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 3866 : return address;
1332 : }
1333 :
1334 : /*
1335 : * Locate a relation by qualified name.
1336 : */
1337 : static ObjectAddress
1338 608 : 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 608 : address.classId = RelationRelationId;
1346 608 : address.objectId = InvalidOid;
1347 608 : address.objectSubId = 0;
1348 :
1349 608 : relation = relation_openrv_extended(makeRangeVarFromNameList(object),
1350 : lockmode, missing_ok);
1351 366 : if (!relation)
1352 0 : return address;
1353 :
1354 366 : switch (objtype)
1355 : {
1356 116 : case OBJECT_INDEX:
1357 116 : 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 116 : 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 80 : case OBJECT_VIEW:
1380 80 : 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 80 : 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 366 : address.objectId = RelationGetRelid(relation);
1407 366 : *relp = relation;
1408 :
1409 366 : 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 1632 : get_object_address_relobject(ObjectType objtype, List *object,
1421 : Relation *relp, bool missing_ok)
1422 : {
1423 : ObjectAddress address;
1424 1632 : Relation relation = NULL;
1425 : int nnames;
1426 : const char *depname;
1427 : List *relname;
1428 : Oid reloid;
1429 :
1430 : /* Extract name of dependent object. */
1431 1632 : depname = strVal(llast(object));
1432 :
1433 : /* Separate relation name from dependent object name. */
1434 1632 : nnames = list_length(object);
1435 1632 : 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 1584 : relname = list_copy_head(object, nnames - 1);
1442 1584 : relation = table_openrv_extended(makeRangeVarFromNameList(relname),
1443 : AccessShareLock,
1444 : missing_ok);
1445 :
1446 1452 : reloid = relation ? RelationGetRelid(relation) : InvalidOid;
1447 :
1448 1452 : switch (objtype)
1449 : {
1450 250 : case OBJECT_RULE:
1451 250 : address.classId = RewriteRelationId;
1452 238 : address.objectId = relation ?
1453 250 : get_rewrite_oid(reloid, depname, missing_ok) : InvalidOid;
1454 238 : address.objectSubId = 0;
1455 238 : break;
1456 802 : case OBJECT_TRIGGER:
1457 802 : address.classId = TriggerRelationId;
1458 778 : address.objectId = relation ?
1459 802 : get_trigger_oid(reloid, depname, missing_ok) : InvalidOid;
1460 778 : address.objectSubId = 0;
1461 778 : break;
1462 224 : case OBJECT_TABCONSTRAINT:
1463 224 : address.classId = ConstraintRelationId;
1464 212 : address.objectId = relation ?
1465 224 : get_relation_constraint_oid(reloid, depname, missing_ok) :
1466 : InvalidOid;
1467 212 : address.objectSubId = 0;
1468 212 : 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 1392 : 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 1344 : *relp = relation;
1492 1344 : return address;
1493 : }
1494 :
1495 : /*
1496 : * Find the ObjectAddress for an attribute.
1497 : */
1498 : static ObjectAddress
1499 302 : 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 302 : if (list_length(object) < 2)
1512 26 : ereport(ERROR,
1513 : (errcode(ERRCODE_SYNTAX_ERROR),
1514 : errmsg("column name must be qualified")));
1515 276 : attname = strVal(llast(object));
1516 276 : relname = list_copy_head(object, list_length(object) - 1);
1517 : /* XXX no missing_ok support here */
1518 276 : relation = relation_openrv(makeRangeVarFromNameList(relname), lockmode);
1519 228 : reloid = RelationGetRelid(relation);
1520 :
1521 : /* Look up attribute and construct return value. */
1522 228 : attnum = get_attnum(reloid, attname);
1523 228 : 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 210 : address.classId = RelationRelationId;
1539 210 : address.objectId = reloid;
1540 210 : address.objectSubId = attnum;
1541 :
1542 210 : *relp = relation;
1543 210 : 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 1864 : get_object_address_type(ObjectType objtype, TypeName *typename, bool missing_ok)
1609 : {
1610 : ObjectAddress address;
1611 : Type tup;
1612 :
1613 1864 : address.classId = TypeRelationId;
1614 1864 : address.objectId = InvalidOid;
1615 1864 : address.objectSubId = 0;
1616 :
1617 1864 : tup = LookupTypeName(NULL, typename, NULL, missing_ok);
1618 1864 : 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 1760 : address.objectId = typeTypeId(tup);
1628 :
1629 1760 : if (objtype == OBJECT_DOMAIN)
1630 : {
1631 574 : 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 1754 : ReleaseSysCache(tup);
1639 :
1640 1754 : return address;
1641 : }
1642 :
1643 : /*
1644 : * Find the ObjectAddress for an opclass or opfamily.
1645 : */
1646 : static ObjectAddress
1647 520 : 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 520 : amoid = get_index_am_oid(strVal(linitial(object)), false);
1654 448 : object = list_copy_tail(object, 1);
1655 :
1656 448 : switch (objtype)
1657 : {
1658 172 : case OBJECT_OPCLASS:
1659 172 : address.classId = OperatorClassRelationId;
1660 172 : address.objectId = get_opclass_oid(amoid, object, missing_ok);
1661 166 : address.objectSubId = 0;
1662 166 : break;
1663 276 : case OBJECT_OPFAMILY:
1664 276 : address.classId = OperatorFamilyRelationId;
1665 276 : address.objectId = get_opfamily_oid(amoid, object, missing_ok);
1666 270 : address.objectSubId = 0;
1667 270 : 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 436 : 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 0 : case DEFACLOBJ_LARGEOBJECT:
2009 0 : objtype_str = "large objects";
2010 0 : break;
2011 18 : default:
2012 18 : ereport(ERROR,
2013 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2014 : errmsg("unrecognized default ACL object type \"%c\"", objtype),
2015 : errhint("Valid object types are \"%c\", \"%c\", \"%c\", \"%c\", \"%c\", \"%c\".",
2016 : DEFACLOBJ_RELATION,
2017 : DEFACLOBJ_SEQUENCE,
2018 : DEFACLOBJ_FUNCTION,
2019 : DEFACLOBJ_TYPE,
2020 : DEFACLOBJ_NAMESPACE,
2021 : DEFACLOBJ_LARGEOBJECT)));
2022 : }
2023 :
2024 : /*
2025 : * Look up user ID. Behave as "default ACL not found" if the user doesn't
2026 : * exist.
2027 : */
2028 24 : tp = SearchSysCache1(AUTHNAME,
2029 : CStringGetDatum(username));
2030 24 : if (!HeapTupleIsValid(tp))
2031 0 : goto not_found;
2032 24 : userid = ((Form_pg_authid) GETSTRUCT(tp))->oid;
2033 24 : ReleaseSysCache(tp);
2034 :
2035 : /*
2036 : * If a schema name was given, look up its OID. If it doesn't exist,
2037 : * behave as "default ACL not found".
2038 : */
2039 24 : if (schema)
2040 : {
2041 12 : schemaid = get_namespace_oid(schema, true);
2042 12 : if (schemaid == InvalidOid)
2043 0 : goto not_found;
2044 : }
2045 : else
2046 12 : schemaid = InvalidOid;
2047 :
2048 : /* Finally, look up the pg_default_acl object */
2049 24 : tp = SearchSysCache3(DEFACLROLENSPOBJ,
2050 : ObjectIdGetDatum(userid),
2051 : ObjectIdGetDatum(schemaid),
2052 : CharGetDatum(objtype));
2053 24 : if (!HeapTupleIsValid(tp))
2054 0 : goto not_found;
2055 :
2056 24 : address.objectId = ((Form_pg_default_acl) GETSTRUCT(tp))->oid;
2057 24 : ReleaseSysCache(tp);
2058 :
2059 24 : return address;
2060 :
2061 0 : not_found:
2062 0 : if (!missing_ok)
2063 : {
2064 0 : if (schema)
2065 0 : ereport(ERROR,
2066 : (errcode(ERRCODE_UNDEFINED_OBJECT),
2067 : errmsg("default ACL for user \"%s\" in schema \"%s\" on %s does not exist",
2068 : username, schema, objtype_str)));
2069 : else
2070 0 : ereport(ERROR,
2071 : (errcode(ERRCODE_UNDEFINED_OBJECT),
2072 : errmsg("default ACL for user \"%s\" on %s does not exist",
2073 : username, objtype_str)));
2074 : }
2075 0 : return address;
2076 : }
2077 :
2078 : /*
2079 : * Convert an array of TEXT into a List of string Values, as emitted by the
2080 : * parser, which is what get_object_address uses as input.
2081 : */
2082 : static List *
2083 3388 : textarray_to_strvaluelist(ArrayType *arr)
2084 : {
2085 : Datum *elems;
2086 : bool *nulls;
2087 : int nelems;
2088 3388 : List *list = NIL;
2089 : int i;
2090 :
2091 3388 : deconstruct_array_builtin(arr, TEXTOID, &elems, &nulls, &nelems);
2092 :
2093 7386 : for (i = 0; i < nelems; i++)
2094 : {
2095 4004 : if (nulls[i])
2096 6 : ereport(ERROR,
2097 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2098 : errmsg("name or argument lists may not contain nulls")));
2099 3998 : list = lappend(list, makeString(TextDatumGetCString(elems[i])));
2100 : }
2101 :
2102 3382 : return list;
2103 : }
2104 :
2105 : /*
2106 : * SQL-callable version of get_object_address
2107 : */
2108 : Datum
2109 2084 : pg_get_object_address(PG_FUNCTION_ARGS)
2110 : {
2111 2084 : char *ttype = TextDatumGetCString(PG_GETARG_DATUM(0));
2112 2084 : ArrayType *namearr = PG_GETARG_ARRAYTYPE_P(1);
2113 2084 : ArrayType *argsarr = PG_GETARG_ARRAYTYPE_P(2);
2114 : int itype;
2115 : ObjectType type;
2116 2084 : List *name = NIL;
2117 2084 : TypeName *typename = NULL;
2118 2084 : List *args = NIL;
2119 2084 : Node *objnode = NULL;
2120 : ObjectAddress addr;
2121 : TupleDesc tupdesc;
2122 : Datum values[3];
2123 : bool nulls[3];
2124 : HeapTuple htup;
2125 : Relation relation;
2126 :
2127 : /* Decode object type, raise error if unknown */
2128 2084 : itype = read_objtype_from_string(ttype);
2129 2078 : if (itype < 0)
2130 36 : ereport(ERROR,
2131 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2132 : errmsg("unsupported object type \"%s\"", ttype)));
2133 2042 : type = (ObjectType) itype;
2134 :
2135 : /*
2136 : * Convert the text array to the representation appropriate for the given
2137 : * object type. Most use a simple string Values list, but there are some
2138 : * exceptions.
2139 : */
2140 2042 : if (type == OBJECT_TYPE || type == OBJECT_DOMAIN || type == OBJECT_CAST ||
2141 1862 : type == OBJECT_TRANSFORM || type == OBJECT_DOMCONSTRAINT)
2142 132 : {
2143 : Datum *elems;
2144 : bool *nulls;
2145 : int nelems;
2146 :
2147 228 : deconstruct_array_builtin(namearr, TEXTOID, &elems, &nulls, &nelems);
2148 228 : if (nelems != 1)
2149 96 : ereport(ERROR,
2150 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2151 : errmsg("name list length must be exactly %d", 1)));
2152 132 : if (nulls[0])
2153 0 : ereport(ERROR,
2154 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2155 : errmsg("name or argument lists may not contain nulls")));
2156 132 : typename = typeStringToTypeName(TextDatumGetCString(elems[0]), NULL);
2157 : }
2158 1814 : else if (type == OBJECT_LARGEOBJECT)
2159 : {
2160 : Datum *elems;
2161 : bool *nulls;
2162 : int nelems;
2163 :
2164 18 : deconstruct_array_builtin(namearr, TEXTOID, &elems, &nulls, &nelems);
2165 18 : if (nelems != 1)
2166 6 : ereport(ERROR,
2167 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2168 : errmsg("name list length must be exactly %d", 1)));
2169 12 : if (nulls[0])
2170 0 : ereport(ERROR,
2171 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2172 : errmsg("large object OID may not be null")));
2173 12 : objnode = (Node *) makeFloat(TextDatumGetCString(elems[0]));
2174 : }
2175 : else
2176 : {
2177 1796 : name = textarray_to_strvaluelist(namearr);
2178 1790 : if (name == NIL)
2179 6 : ereport(ERROR,
2180 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2181 : errmsg("name list length must be at least %d", 1)));
2182 : }
2183 :
2184 : /*
2185 : * If args are given, decode them according to the object type.
2186 : */
2187 1928 : if (type == OBJECT_AGGREGATE ||
2188 1832 : type == OBJECT_FUNCTION ||
2189 1784 : type == OBJECT_PROCEDURE ||
2190 1784 : type == OBJECT_ROUTINE ||
2191 1736 : type == OBJECT_OPERATOR ||
2192 1712 : type == OBJECT_CAST ||
2193 1652 : type == OBJECT_AMOP ||
2194 : type == OBJECT_AMPROC)
2195 336 : {
2196 : /* in these cases, the args list must be of TypeName */
2197 : Datum *elems;
2198 : bool *nulls;
2199 : int nelems;
2200 : int i;
2201 :
2202 336 : deconstruct_array_builtin(argsarr, TEXTOID, &elems, &nulls, &nelems);
2203 :
2204 336 : args = NIL;
2205 642 : for (i = 0; i < nelems; i++)
2206 : {
2207 306 : if (nulls[i])
2208 0 : ereport(ERROR,
2209 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2210 : errmsg("name or argument lists may not contain nulls")));
2211 306 : args = lappend(args,
2212 306 : typeStringToTypeName(TextDatumGetCString(elems[i]),
2213 : NULL));
2214 : }
2215 : }
2216 : else
2217 : {
2218 : /* For all other object types, use string Values */
2219 1592 : args = textarray_to_strvaluelist(argsarr);
2220 : }
2221 :
2222 : /*
2223 : * get_object_address is pretty sensitive to the length of its input
2224 : * lists; check that they're what it wants.
2225 : */
2226 1928 : switch (type)
2227 : {
2228 96 : case OBJECT_PUBLICATION_NAMESPACE:
2229 : case OBJECT_USER_MAPPING:
2230 96 : if (list_length(name) != 1)
2231 48 : ereport(ERROR,
2232 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2233 : errmsg("name list length must be exactly %d", 1)));
2234 : /* fall through to check args length */
2235 : /* FALLTHROUGH */
2236 : case OBJECT_DOMCONSTRAINT:
2237 : case OBJECT_CAST:
2238 : case OBJECT_PUBLICATION_REL:
2239 : case OBJECT_DEFACL:
2240 : case OBJECT_TRANSFORM:
2241 228 : if (list_length(args) != 1)
2242 66 : ereport(ERROR,
2243 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2244 : errmsg("argument list length must be exactly %d", 1)));
2245 162 : break;
2246 96 : case OBJECT_OPFAMILY:
2247 : case OBJECT_OPCLASS:
2248 96 : if (list_length(name) < 2)
2249 24 : ereport(ERROR,
2250 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2251 : errmsg("name list length must be at least %d", 2)));
2252 72 : break;
2253 120 : case OBJECT_AMOP:
2254 : case OBJECT_AMPROC:
2255 120 : if (list_length(name) < 3)
2256 48 : ereport(ERROR,
2257 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2258 : errmsg("name list length must be at least %d", 3)));
2259 : /* fall through to check args length */
2260 : /* FALLTHROUGH */
2261 : case OBJECT_OPERATOR:
2262 120 : if (list_length(args) != 2)
2263 60 : ereport(ERROR,
2264 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2265 : errmsg("argument list length must be exactly %d", 2)));
2266 60 : break;
2267 1388 : default:
2268 1388 : break;
2269 : }
2270 :
2271 : /*
2272 : * Now build the Node type that get_object_address() expects for the given
2273 : * type.
2274 : */
2275 1682 : switch (type)
2276 : {
2277 984 : case OBJECT_TABLE:
2278 : case OBJECT_SEQUENCE:
2279 : case OBJECT_VIEW:
2280 : case OBJECT_MATVIEW:
2281 : case OBJECT_INDEX:
2282 : case OBJECT_FOREIGN_TABLE:
2283 : case OBJECT_COLUMN:
2284 : case OBJECT_ATTRIBUTE:
2285 : case OBJECT_COLLATION:
2286 : case OBJECT_CONVERSION:
2287 : case OBJECT_STATISTIC_EXT:
2288 : case OBJECT_TSPARSER:
2289 : case OBJECT_TSDICTIONARY:
2290 : case OBJECT_TSTEMPLATE:
2291 : case OBJECT_TSCONFIGURATION:
2292 : case OBJECT_DEFAULT:
2293 : case OBJECT_POLICY:
2294 : case OBJECT_RULE:
2295 : case OBJECT_TRIGGER:
2296 : case OBJECT_TABCONSTRAINT:
2297 : case OBJECT_OPCLASS:
2298 : case OBJECT_OPFAMILY:
2299 984 : objnode = (Node *) name;
2300 984 : break;
2301 260 : case OBJECT_ACCESS_METHOD:
2302 : case OBJECT_DATABASE:
2303 : case OBJECT_EVENT_TRIGGER:
2304 : case OBJECT_EXTENSION:
2305 : case OBJECT_FDW:
2306 : case OBJECT_FOREIGN_SERVER:
2307 : case OBJECT_LANGUAGE:
2308 : case OBJECT_PARAMETER_ACL:
2309 : case OBJECT_PUBLICATION:
2310 : case OBJECT_ROLE:
2311 : case OBJECT_SCHEMA:
2312 : case OBJECT_SUBSCRIPTION:
2313 : case OBJECT_TABLESPACE:
2314 260 : if (list_length(name) != 1)
2315 72 : ereport(ERROR,
2316 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2317 : errmsg("name list length must be exactly %d", 1)));
2318 188 : objnode = linitial(name);
2319 188 : break;
2320 60 : case OBJECT_TYPE:
2321 : case OBJECT_DOMAIN:
2322 60 : objnode = (Node *) typename;
2323 60 : break;
2324 54 : case OBJECT_CAST:
2325 : case OBJECT_DOMCONSTRAINT:
2326 : case OBJECT_TRANSFORM:
2327 54 : objnode = (Node *) list_make2(typename, linitial(args));
2328 54 : break;
2329 30 : case OBJECT_PUBLICATION_REL:
2330 30 : objnode = (Node *) list_make2(name, linitial(args));
2331 30 : break;
2332 36 : case OBJECT_PUBLICATION_NAMESPACE:
2333 : case OBJECT_USER_MAPPING:
2334 36 : objnode = (Node *) list_make2(linitial(name), linitial(args));
2335 36 : break;
2336 42 : case OBJECT_DEFACL:
2337 42 : objnode = (Node *) lcons(linitial(args), name);
2338 42 : break;
2339 48 : case OBJECT_AMOP:
2340 : case OBJECT_AMPROC:
2341 48 : objnode = (Node *) list_make2(name, args);
2342 48 : break;
2343 156 : case OBJECT_FUNCTION:
2344 : case OBJECT_PROCEDURE:
2345 : case OBJECT_ROUTINE:
2346 : case OBJECT_AGGREGATE:
2347 : case OBJECT_OPERATOR:
2348 : {
2349 156 : ObjectWithArgs *owa = makeNode(ObjectWithArgs);
2350 :
2351 156 : owa->objname = name;
2352 156 : owa->objargs = args;
2353 156 : objnode = (Node *) owa;
2354 156 : break;
2355 : }
2356 12 : case OBJECT_LARGEOBJECT:
2357 : /* already handled above */
2358 12 : break;
2359 : /* no default, to let compiler warn about missing case */
2360 : }
2361 :
2362 1610 : if (objnode == NULL)
2363 0 : elog(ERROR, "unrecognized object type: %d", type);
2364 :
2365 1610 : addr = get_object_address(type, objnode,
2366 : &relation, AccessShareLock, false);
2367 :
2368 : /* We don't need the relcache entry, thank you very much */
2369 620 : if (relation)
2370 192 : relation_close(relation, AccessShareLock);
2371 :
2372 620 : if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
2373 0 : elog(ERROR, "return type must be a row type");
2374 :
2375 620 : values[0] = ObjectIdGetDatum(addr.classId);
2376 620 : values[1] = ObjectIdGetDatum(addr.objectId);
2377 620 : values[2] = Int32GetDatum(addr.objectSubId);
2378 620 : nulls[0] = false;
2379 620 : nulls[1] = false;
2380 620 : nulls[2] = false;
2381 :
2382 620 : htup = heap_form_tuple(tupdesc, values, nulls);
2383 :
2384 620 : PG_RETURN_DATUM(HeapTupleGetDatum(htup));
2385 : }
2386 :
2387 : /*
2388 : * Check ownership of an object previously identified by get_object_address.
2389 : */
2390 : void
2391 10032 : check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address,
2392 : Node *object, Relation relation)
2393 : {
2394 10032 : switch (objtype)
2395 : {
2396 1752 : case OBJECT_INDEX:
2397 : case OBJECT_SEQUENCE:
2398 : case OBJECT_TABLE:
2399 : case OBJECT_VIEW:
2400 : case OBJECT_MATVIEW:
2401 : case OBJECT_FOREIGN_TABLE:
2402 : case OBJECT_COLUMN:
2403 : case OBJECT_RULE:
2404 : case OBJECT_TRIGGER:
2405 : case OBJECT_POLICY:
2406 : case OBJECT_TABCONSTRAINT:
2407 1752 : if (!object_ownercheck(RelationRelationId, RelationGetRelid(relation), roleid))
2408 22 : aclcheck_error(ACLCHECK_NOT_OWNER, objtype,
2409 22 : RelationGetRelationName(relation));
2410 1730 : break;
2411 92 : case OBJECT_TYPE:
2412 : case OBJECT_DOMAIN:
2413 : case OBJECT_ATTRIBUTE:
2414 92 : if (!object_ownercheck(address.classId, address.objectId, roleid))
2415 0 : aclcheck_error_type(ACLCHECK_NOT_OWNER, address.objectId);
2416 92 : break;
2417 32 : case OBJECT_DOMCONSTRAINT:
2418 : {
2419 : HeapTuple tuple;
2420 : Oid contypid;
2421 :
2422 32 : tuple = SearchSysCache1(CONSTROID,
2423 : ObjectIdGetDatum(address.objectId));
2424 32 : if (!HeapTupleIsValid(tuple))
2425 0 : elog(ERROR, "constraint with OID %u does not exist",
2426 : address.objectId);
2427 :
2428 32 : contypid = ((Form_pg_constraint) GETSTRUCT(tuple))->contypid;
2429 :
2430 32 : ReleaseSysCache(tuple);
2431 :
2432 : /*
2433 : * Fallback to type ownership check in this case as this is
2434 : * what domain constraints rely on.
2435 : */
2436 32 : if (!object_ownercheck(TypeRelationId, contypid, roleid))
2437 6 : aclcheck_error_type(ACLCHECK_NOT_OWNER, contypid);
2438 : }
2439 26 : break;
2440 440 : case OBJECT_AGGREGATE:
2441 : case OBJECT_FUNCTION:
2442 : case OBJECT_PROCEDURE:
2443 : case OBJECT_ROUTINE:
2444 : case OBJECT_OPERATOR:
2445 440 : if (!object_ownercheck(address.classId, address.objectId, roleid))
2446 18 : aclcheck_error(ACLCHECK_NOT_OWNER, objtype,
2447 18 : NameListToString((castNode(ObjectWithArgs, object))->objname));
2448 422 : break;
2449 1948 : case OBJECT_DATABASE:
2450 : case OBJECT_EVENT_TRIGGER:
2451 : case OBJECT_EXTENSION:
2452 : case OBJECT_FDW:
2453 : case OBJECT_FOREIGN_SERVER:
2454 : case OBJECT_LANGUAGE:
2455 : case OBJECT_PUBLICATION:
2456 : case OBJECT_SCHEMA:
2457 : case OBJECT_SUBSCRIPTION:
2458 : case OBJECT_TABLESPACE:
2459 1948 : if (!object_ownercheck(address.classId, address.objectId, roleid))
2460 42 : aclcheck_error(ACLCHECK_NOT_OWNER, objtype,
2461 42 : strVal(object));
2462 1906 : break;
2463 5534 : case OBJECT_COLLATION:
2464 : case OBJECT_CONVERSION:
2465 : case OBJECT_OPCLASS:
2466 : case OBJECT_OPFAMILY:
2467 : case OBJECT_STATISTIC_EXT:
2468 : case OBJECT_TSDICTIONARY:
2469 : case OBJECT_TSCONFIGURATION:
2470 5534 : if (!object_ownercheck(address.classId, address.objectId, roleid))
2471 12 : aclcheck_error(ACLCHECK_NOT_OWNER, objtype,
2472 12 : NameListToString(castNode(List, object)));
2473 5522 : break;
2474 28 : case OBJECT_LARGEOBJECT:
2475 28 : if (!lo_compat_privileges &&
2476 28 : !object_ownercheck(address.classId, address.objectId, roleid))
2477 0 : ereport(ERROR,
2478 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2479 : errmsg("must be owner of large object %u",
2480 : address.objectId)));
2481 28 : break;
2482 28 : case OBJECT_CAST:
2483 : {
2484 : /* We can only check permissions on the source/target types */
2485 28 : TypeName *sourcetype = linitial_node(TypeName, castNode(List, object));
2486 28 : TypeName *targettype = lsecond_node(TypeName, castNode(List, object));
2487 28 : Oid sourcetypeid = typenameTypeId(NULL, sourcetype);
2488 28 : Oid targettypeid = typenameTypeId(NULL, targettype);
2489 :
2490 28 : if (!object_ownercheck(TypeRelationId, sourcetypeid, roleid)
2491 0 : && !object_ownercheck(TypeRelationId, targettypeid, roleid))
2492 0 : ereport(ERROR,
2493 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2494 : errmsg("must be owner of type %s or type %s",
2495 : format_type_be(sourcetypeid),
2496 : format_type_be(targettypeid))));
2497 : }
2498 28 : break;
2499 22 : case OBJECT_TRANSFORM:
2500 : {
2501 22 : TypeName *typename = linitial_node(TypeName, castNode(List, object));
2502 22 : Oid typeid = typenameTypeId(NULL, typename);
2503 :
2504 22 : if (!object_ownercheck(TypeRelationId, typeid, roleid))
2505 0 : aclcheck_error_type(ACLCHECK_NOT_OWNER, typeid);
2506 : }
2507 22 : break;
2508 24 : case OBJECT_ROLE:
2509 :
2510 : /*
2511 : * We treat roles as being "owned" by those with CREATEROLE priv,
2512 : * provided that they also have admin option on the role.
2513 : *
2514 : * However, superusers are only owned by superusers.
2515 : */
2516 24 : if (superuser_arg(address.objectId))
2517 : {
2518 0 : if (!superuser_arg(roleid))
2519 0 : ereport(ERROR,
2520 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2521 : errmsg("permission denied"),
2522 : errdetail("The current user must have the %s attribute.",
2523 : "SUPERUSER")));
2524 : }
2525 : else
2526 : {
2527 24 : if (!has_createrole_privilege(roleid))
2528 2 : ereport(ERROR,
2529 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2530 : errmsg("permission denied"),
2531 : errdetail("The current user must have the %s attribute.",
2532 : "CREATEROLE")));
2533 22 : if (!is_admin_of_role(roleid, address.objectId))
2534 6 : ereport(ERROR,
2535 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2536 : errmsg("permission denied"),
2537 : errdetail("The current user must have the %s option on role \"%s\".",
2538 : "ADMIN",
2539 : GetUserNameFromId(address.objectId,
2540 : true))));
2541 : }
2542 16 : break;
2543 132 : case OBJECT_TSPARSER:
2544 : case OBJECT_TSTEMPLATE:
2545 : case OBJECT_ACCESS_METHOD:
2546 : case OBJECT_PARAMETER_ACL:
2547 : /* We treat these object types as being owned by superusers */
2548 132 : if (!superuser_arg(roleid))
2549 0 : ereport(ERROR,
2550 : (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
2551 : errmsg("must be superuser")));
2552 132 : break;
2553 0 : case OBJECT_AMOP:
2554 : case OBJECT_AMPROC:
2555 : case OBJECT_DEFAULT:
2556 : case OBJECT_DEFACL:
2557 : case OBJECT_PUBLICATION_NAMESPACE:
2558 : case OBJECT_PUBLICATION_REL:
2559 : case OBJECT_USER_MAPPING:
2560 : /* These are currently not supported or don't make sense here. */
2561 0 : elog(ERROR, "unsupported object type: %d", (int) objtype);
2562 : break;
2563 : }
2564 9924 : }
2565 :
2566 : /*
2567 : * get_object_namespace
2568 : *
2569 : * Find the schema containing the specified object. For non-schema objects,
2570 : * this function returns InvalidOid.
2571 : */
2572 : Oid
2573 8088 : get_object_namespace(const ObjectAddress *address)
2574 : {
2575 : int cache;
2576 : HeapTuple tuple;
2577 : Oid oid;
2578 : const ObjectPropertyType *property;
2579 :
2580 : /* If not owned by a namespace, just return InvalidOid. */
2581 8088 : property = get_object_property_data(address->classId);
2582 8088 : if (property->attnum_namespace == InvalidAttrNumber)
2583 2596 : return InvalidOid;
2584 :
2585 : /* Currently, we can only handle object types with system caches. */
2586 5492 : cache = property->oid_catcache_id;
2587 : Assert(cache != -1);
2588 :
2589 : /* Fetch tuple from syscache and extract namespace attribute. */
2590 5492 : tuple = SearchSysCache1(cache, ObjectIdGetDatum(address->objectId));
2591 5492 : if (!HeapTupleIsValid(tuple))
2592 0 : elog(ERROR, "cache lookup failed for cache %d oid %u",
2593 : cache, address->objectId);
2594 5492 : oid = DatumGetObjectId(SysCacheGetAttrNotNull(cache,
2595 : tuple,
2596 5492 : property->attnum_namespace));
2597 5492 : ReleaseSysCache(tuple);
2598 :
2599 5492 : return oid;
2600 : }
2601 :
2602 : /*
2603 : * Return ObjectType for the given object type as given by
2604 : * getObjectTypeDescription; if no valid ObjectType code exists, but it's a
2605 : * possible output type from getObjectTypeDescription, return -1.
2606 : * Otherwise, an error is thrown.
2607 : */
2608 : int
2609 2084 : read_objtype_from_string(const char *objtype)
2610 : {
2611 : int i;
2612 :
2613 61394 : for (i = 0; i < lengthof(ObjectTypeMap); i++)
2614 : {
2615 61388 : if (strcmp(ObjectTypeMap[i].tm_name, objtype) == 0)
2616 2078 : return ObjectTypeMap[i].tm_type;
2617 : }
2618 6 : ereport(ERROR,
2619 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2620 : errmsg("unrecognized object type \"%s\"", objtype)));
2621 :
2622 : return -1; /* keep compiler quiet */
2623 : }
2624 :
2625 : /*
2626 : * Interfaces to reference fields of ObjectPropertyType
2627 : */
2628 : const char *
2629 0 : get_object_class_descr(Oid class_id)
2630 : {
2631 0 : const ObjectPropertyType *prop = get_object_property_data(class_id);
2632 :
2633 0 : return prop->class_descr;
2634 : }
2635 :
2636 : Oid
2637 2424 : get_object_oid_index(Oid class_id)
2638 : {
2639 2424 : const ObjectPropertyType *prop = get_object_property_data(class_id);
2640 :
2641 2424 : return prop->oid_index_oid;
2642 : }
2643 :
2644 : int
2645 74424 : get_object_catcache_oid(Oid class_id)
2646 : {
2647 74424 : const ObjectPropertyType *prop = get_object_property_data(class_id);
2648 :
2649 74424 : return prop->oid_catcache_id;
2650 : }
2651 :
2652 : int
2653 708 : get_object_catcache_name(Oid class_id)
2654 : {
2655 708 : const ObjectPropertyType *prop = get_object_property_data(class_id);
2656 :
2657 708 : return prop->name_catcache_id;
2658 : }
2659 :
2660 : AttrNumber
2661 9220 : get_object_attnum_oid(Oid class_id)
2662 : {
2663 9220 : const ObjectPropertyType *prop = get_object_property_data(class_id);
2664 :
2665 9220 : return prop->attnum_oid;
2666 : }
2667 :
2668 : AttrNumber
2669 16334 : get_object_attnum_name(Oid class_id)
2670 : {
2671 16334 : const ObjectPropertyType *prop = get_object_property_data(class_id);
2672 :
2673 16334 : return prop->attnum_name;
2674 : }
2675 :
2676 : AttrNumber
2677 8206 : get_object_attnum_namespace(Oid class_id)
2678 : {
2679 8206 : const ObjectPropertyType *prop = get_object_property_data(class_id);
2680 :
2681 8206 : return prop->attnum_namespace;
2682 : }
2683 :
2684 : AttrNumber
2685 64476 : get_object_attnum_owner(Oid class_id)
2686 : {
2687 64476 : const ObjectPropertyType *prop = get_object_property_data(class_id);
2688 :
2689 64476 : return prop->attnum_owner;
2690 : }
2691 :
2692 : AttrNumber
2693 73248 : get_object_attnum_acl(Oid class_id)
2694 : {
2695 73248 : const ObjectPropertyType *prop = get_object_property_data(class_id);
2696 :
2697 73248 : return prop->attnum_acl;
2698 : }
2699 :
2700 : /*
2701 : * get_object_type
2702 : *
2703 : * Return the object type associated with a given object. This routine
2704 : * is primarily used to determine the object type to mention in ACL check
2705 : * error messages, so it's desirable for it to avoid failing.
2706 : */
2707 : ObjectType
2708 56308 : get_object_type(Oid class_id, Oid object_id)
2709 : {
2710 56308 : const ObjectPropertyType *prop = get_object_property_data(class_id);
2711 :
2712 56308 : if (prop->objtype == OBJECT_TABLE)
2713 : {
2714 : /*
2715 : * If the property data says it's a table, dig a little deeper to get
2716 : * the real relation kind, so that callers can produce more precise
2717 : * error messages.
2718 : */
2719 0 : return get_relkind_objtype(get_rel_relkind(object_id));
2720 : }
2721 : else
2722 56308 : return prop->objtype;
2723 : }
2724 :
2725 : bool
2726 4956 : get_object_namensp_unique(Oid class_id)
2727 : {
2728 4956 : const ObjectPropertyType *prop = get_object_property_data(class_id);
2729 :
2730 4956 : return prop->is_nsp_name_unique;
2731 : }
2732 :
2733 : /*
2734 : * Return whether we have useful data for the given object class in the
2735 : * ObjectProperty table.
2736 : */
2737 : bool
2738 6286 : is_objectclass_supported(Oid class_id)
2739 : {
2740 : int index;
2741 :
2742 149224 : for (index = 0; index < lengthof(ObjectProperty); index++)
2743 : {
2744 148698 : if (ObjectProperty[index].class_oid == class_id)
2745 5760 : return true;
2746 : }
2747 :
2748 526 : return false;
2749 : }
2750 :
2751 : /*
2752 : * Find ObjectProperty structure by class_id.
2753 : */
2754 : static const ObjectPropertyType *
2755 318392 : get_object_property_data(Oid class_id)
2756 : {
2757 : static const ObjectPropertyType *prop_last = NULL;
2758 : int index;
2759 :
2760 : /*
2761 : * A shortcut to speed up multiple consecutive lookups of a particular
2762 : * object class.
2763 : */
2764 318392 : if (prop_last && prop_last->class_oid == class_id)
2765 303308 : return prop_last;
2766 :
2767 271896 : for (index = 0; index < lengthof(ObjectProperty); index++)
2768 : {
2769 271896 : if (ObjectProperty[index].class_oid == class_id)
2770 : {
2771 15084 : prop_last = &ObjectProperty[index];
2772 15084 : return &ObjectProperty[index];
2773 : }
2774 : }
2775 :
2776 0 : ereport(ERROR,
2777 : (errmsg_internal("unrecognized class ID: %u", class_id)));
2778 :
2779 : return NULL; /* keep MSC compiler happy */
2780 : }
2781 :
2782 : /*
2783 : * Return a copy of the tuple for the object with the given object OID, from
2784 : * the given catalog (which must have been opened by the caller and suitably
2785 : * locked). NULL is returned if the OID is not found.
2786 : *
2787 : * We try a syscache first, if available.
2788 : */
2789 : HeapTuple
2790 6722 : get_catalog_object_by_oid(Relation catalog, AttrNumber oidcol, Oid objectId)
2791 : {
2792 : return
2793 6722 : get_catalog_object_by_oid_extended(catalog, oidcol, objectId, false);
2794 : }
2795 :
2796 : /*
2797 : * Same as get_catalog_object_by_oid(), but with an additional "locktup"
2798 : * argument controlling whether to acquire a LOCKTAG_TUPLE at mode
2799 : * InplaceUpdateTupleLock. See README.tuplock section "Locking to write
2800 : * inplace-updated tables".
2801 : */
2802 : HeapTuple
2803 8676 : get_catalog_object_by_oid_extended(Relation catalog,
2804 : AttrNumber oidcol,
2805 : Oid objectId,
2806 : bool locktup)
2807 : {
2808 : HeapTuple tuple;
2809 8676 : Oid classId = RelationGetRelid(catalog);
2810 8676 : int oidCacheId = get_object_catcache_oid(classId);
2811 :
2812 8676 : if (oidCacheId > 0)
2813 : {
2814 7794 : if (locktup)
2815 1934 : tuple = SearchSysCacheLockedCopy1(oidCacheId,
2816 : ObjectIdGetDatum(objectId));
2817 : else
2818 5860 : tuple = SearchSysCacheCopy1(oidCacheId,
2819 : ObjectIdGetDatum(objectId));
2820 7794 : if (!HeapTupleIsValid(tuple)) /* should not happen */
2821 192 : return NULL;
2822 : }
2823 : else
2824 : {
2825 882 : Oid oidIndexId = get_object_oid_index(classId);
2826 : SysScanDesc scan;
2827 : ScanKeyData skey;
2828 :
2829 : Assert(OidIsValid(oidIndexId));
2830 :
2831 882 : ScanKeyInit(&skey,
2832 : oidcol,
2833 : BTEqualStrategyNumber, F_OIDEQ,
2834 : ObjectIdGetDatum(objectId));
2835 :
2836 882 : scan = systable_beginscan(catalog, oidIndexId, true,
2837 : NULL, 1, &skey);
2838 882 : tuple = systable_getnext(scan);
2839 882 : if (!HeapTupleIsValid(tuple))
2840 : {
2841 102 : systable_endscan(scan);
2842 102 : return NULL;
2843 : }
2844 :
2845 780 : if (locktup)
2846 20 : LockTuple(catalog, &tuple->t_self, InplaceUpdateTupleLock);
2847 :
2848 780 : tuple = heap_copytuple(tuple);
2849 :
2850 780 : systable_endscan(scan);
2851 : }
2852 :
2853 8382 : return tuple;
2854 : }
2855 :
2856 : /*
2857 : * getPublicationSchemaInfo
2858 : *
2859 : * Get publication name and schema name from the object address into pubname and
2860 : * nspname. Both pubname and nspname are palloc'd strings which will be freed by
2861 : * the caller.
2862 : */
2863 : static bool
2864 202 : getPublicationSchemaInfo(const ObjectAddress *object, bool missing_ok,
2865 : char **pubname, char **nspname)
2866 : {
2867 : HeapTuple tup;
2868 : Form_pg_publication_namespace pnform;
2869 :
2870 202 : tup = SearchSysCache1(PUBLICATIONNAMESPACE,
2871 : ObjectIdGetDatum(object->objectId));
2872 202 : if (!HeapTupleIsValid(tup))
2873 : {
2874 18 : if (!missing_ok)
2875 0 : elog(ERROR, "cache lookup failed for publication schema %u",
2876 : object->objectId);
2877 18 : return false;
2878 : }
2879 :
2880 184 : pnform = (Form_pg_publication_namespace) GETSTRUCT(tup);
2881 184 : *pubname = get_publication_name(pnform->pnpubid, missing_ok);
2882 184 : if (!(*pubname))
2883 : {
2884 0 : ReleaseSysCache(tup);
2885 0 : return false;
2886 : }
2887 :
2888 184 : *nspname = get_namespace_name(pnform->pnnspid);
2889 184 : if (!(*nspname))
2890 : {
2891 0 : Oid schemaid = pnform->pnnspid;
2892 :
2893 0 : pfree(*pubname);
2894 0 : ReleaseSysCache(tup);
2895 0 : if (!missing_ok)
2896 0 : elog(ERROR, "cache lookup failed for schema %u",
2897 : schemaid);
2898 0 : return false;
2899 : }
2900 :
2901 184 : ReleaseSysCache(tup);
2902 184 : return true;
2903 : }
2904 :
2905 : /*
2906 : * getObjectDescription: build an object description for messages
2907 : *
2908 : * The result is a palloc'd string. NULL is returned for an undefined
2909 : * object if missing_ok is true, else an error is generated.
2910 : */
2911 : char *
2912 172534 : getObjectDescription(const ObjectAddress *object, bool missing_ok)
2913 : {
2914 : StringInfoData buffer;
2915 :
2916 172534 : initStringInfo(&buffer);
2917 :
2918 172534 : switch (object->classId)
2919 : {
2920 49144 : case RelationRelationId:
2921 49144 : if (object->objectSubId == 0)
2922 46082 : getRelationDescription(&buffer, object->objectId, missing_ok);
2923 : else
2924 : {
2925 : /* column, not whole relation */
2926 : StringInfoData rel;
2927 3062 : char *attname = get_attname(object->objectId,
2928 3062 : object->objectSubId,
2929 : missing_ok);
2930 :
2931 3062 : if (!attname)
2932 6 : break;
2933 :
2934 3056 : initStringInfo(&rel);
2935 3056 : getRelationDescription(&rel, object->objectId, missing_ok);
2936 : /* translator: second %s is, e.g., "table %s" */
2937 3056 : appendStringInfo(&buffer, _("column %s of %s"),
2938 : attname, rel.data);
2939 3056 : pfree(rel.data);
2940 : }
2941 49138 : break;
2942 :
2943 3636 : case ProcedureRelationId:
2944 : {
2945 3636 : bits16 flags = FORMAT_PROC_INVALID_AS_NULL;
2946 3636 : char *proname = format_procedure_extended(object->objectId,
2947 : flags);
2948 :
2949 3636 : if (proname == NULL)
2950 6 : break;
2951 :
2952 3630 : appendStringInfo(&buffer, _("function %s"), proname);
2953 3630 : break;
2954 : }
2955 :
2956 71492 : case TypeRelationId:
2957 : {
2958 71492 : bits16 flags = FORMAT_TYPE_INVALID_AS_NULL;
2959 71492 : char *typname = format_type_extended(object->objectId, -1,
2960 : flags);
2961 :
2962 71492 : if (typname == NULL)
2963 6 : break;
2964 :
2965 71486 : appendStringInfo(&buffer, _("type %s"), typname);
2966 71486 : break;
2967 : }
2968 :
2969 270 : case CastRelationId:
2970 : {
2971 : Relation castDesc;
2972 : ScanKeyData skey[1];
2973 : SysScanDesc rcscan;
2974 : HeapTuple tup;
2975 : Form_pg_cast castForm;
2976 :
2977 270 : castDesc = table_open(CastRelationId, AccessShareLock);
2978 :
2979 270 : ScanKeyInit(&skey[0],
2980 : Anum_pg_cast_oid,
2981 : BTEqualStrategyNumber, F_OIDEQ,
2982 : ObjectIdGetDatum(object->objectId));
2983 :
2984 270 : rcscan = systable_beginscan(castDesc, CastOidIndexId, true,
2985 : NULL, 1, skey);
2986 :
2987 270 : tup = systable_getnext(rcscan);
2988 :
2989 270 : if (!HeapTupleIsValid(tup))
2990 : {
2991 6 : if (!missing_ok)
2992 0 : elog(ERROR, "could not find tuple for cast %u",
2993 : object->objectId);
2994 :
2995 6 : systable_endscan(rcscan);
2996 6 : table_close(castDesc, AccessShareLock);
2997 6 : break;
2998 : }
2999 :
3000 264 : castForm = (Form_pg_cast) GETSTRUCT(tup);
3001 :
3002 264 : appendStringInfo(&buffer, _("cast from %s to %s"),
3003 : format_type_be(castForm->castsource),
3004 : format_type_be(castForm->casttarget));
3005 :
3006 264 : systable_endscan(rcscan);
3007 264 : table_close(castDesc, AccessShareLock);
3008 264 : break;
3009 : }
3010 :
3011 72 : case CollationRelationId:
3012 : {
3013 : HeapTuple collTup;
3014 : Form_pg_collation coll;
3015 : char *nspname;
3016 :
3017 72 : collTup = SearchSysCache1(COLLOID,
3018 : ObjectIdGetDatum(object->objectId));
3019 72 : if (!HeapTupleIsValid(collTup))
3020 : {
3021 6 : if (!missing_ok)
3022 0 : elog(ERROR, "cache lookup failed for collation %u",
3023 : object->objectId);
3024 6 : break;
3025 : }
3026 :
3027 66 : coll = (Form_pg_collation) GETSTRUCT(collTup);
3028 :
3029 : /* Qualify the name if not visible in search path */
3030 66 : if (CollationIsVisible(object->objectId))
3031 66 : nspname = NULL;
3032 : else
3033 0 : nspname = get_namespace_name(coll->collnamespace);
3034 :
3035 66 : appendStringInfo(&buffer, _("collation %s"),
3036 : quote_qualified_identifier(nspname,
3037 66 : NameStr(coll->collname)));
3038 66 : ReleaseSysCache(collTup);
3039 66 : break;
3040 : }
3041 :
3042 24838 : case ConstraintRelationId:
3043 : {
3044 : HeapTuple conTup;
3045 : Form_pg_constraint con;
3046 :
3047 24838 : conTup = SearchSysCache1(CONSTROID,
3048 : ObjectIdGetDatum(object->objectId));
3049 24838 : if (!HeapTupleIsValid(conTup))
3050 : {
3051 6 : if (!missing_ok)
3052 0 : elog(ERROR, "cache lookup failed for constraint %u",
3053 : object->objectId);
3054 6 : break;
3055 : }
3056 :
3057 24832 : con = (Form_pg_constraint) GETSTRUCT(conTup);
3058 :
3059 24832 : if (OidIsValid(con->conrelid))
3060 : {
3061 : StringInfoData rel;
3062 :
3063 24542 : initStringInfo(&rel);
3064 24542 : getRelationDescription(&rel, con->conrelid, false);
3065 : /* translator: second %s is, e.g., "table %s" */
3066 24542 : appendStringInfo(&buffer, _("constraint %s on %s"),
3067 24542 : NameStr(con->conname), rel.data);
3068 24542 : pfree(rel.data);
3069 : }
3070 : else
3071 : {
3072 290 : appendStringInfo(&buffer, _("constraint %s"),
3073 290 : NameStr(con->conname));
3074 : }
3075 :
3076 24832 : ReleaseSysCache(conTup);
3077 24832 : break;
3078 : }
3079 :
3080 36 : case ConversionRelationId:
3081 : {
3082 : HeapTuple conTup;
3083 : Form_pg_conversion conv;
3084 : char *nspname;
3085 :
3086 36 : conTup = SearchSysCache1(CONVOID,
3087 : ObjectIdGetDatum(object->objectId));
3088 36 : if (!HeapTupleIsValid(conTup))
3089 : {
3090 6 : if (!missing_ok)
3091 0 : elog(ERROR, "cache lookup failed for conversion %u",
3092 : object->objectId);
3093 6 : break;
3094 : }
3095 :
3096 30 : conv = (Form_pg_conversion) GETSTRUCT(conTup);
3097 :
3098 : /* Qualify the name if not visible in search path */
3099 30 : if (ConversionIsVisible(object->objectId))
3100 18 : nspname = NULL;
3101 : else
3102 12 : nspname = get_namespace_name(conv->connamespace);
3103 :
3104 30 : appendStringInfo(&buffer, _("conversion %s"),
3105 : quote_qualified_identifier(nspname,
3106 30 : NameStr(conv->conname)));
3107 30 : ReleaseSysCache(conTup);
3108 30 : break;
3109 : }
3110 :
3111 2634 : case AttrDefaultRelationId:
3112 : {
3113 : ObjectAddress colobject;
3114 :
3115 2634 : colobject = GetAttrDefaultColumnAddress(object->objectId);
3116 :
3117 2634 : if (!OidIsValid(colobject.objectId))
3118 : {
3119 6 : if (!missing_ok)
3120 0 : elog(ERROR, "could not find tuple for attrdef %u",
3121 : object->objectId);
3122 6 : break;
3123 : }
3124 :
3125 : /* translator: %s is typically "column %s of table %s" */
3126 2628 : appendStringInfo(&buffer, _("default value for %s"),
3127 : getObjectDescription(&colobject, false));
3128 2628 : break;
3129 : }
3130 :
3131 24 : case LanguageRelationId:
3132 : {
3133 24 : char *langname = get_language_name(object->objectId,
3134 : missing_ok);
3135 :
3136 24 : if (langname)
3137 18 : appendStringInfo(&buffer, _("language %s"),
3138 : get_language_name(object->objectId, false));
3139 24 : break;
3140 : }
3141 :
3142 6 : case LargeObjectRelationId:
3143 6 : if (!LargeObjectExists(object->objectId))
3144 6 : break;
3145 0 : appendStringInfo(&buffer, _("large object %u"),
3146 : object->objectId);
3147 0 : break;
3148 :
3149 724 : case OperatorRelationId:
3150 : {
3151 724 : bits16 flags = FORMAT_OPERATOR_INVALID_AS_NULL;
3152 724 : char *oprname = format_operator_extended(object->objectId,
3153 : flags);
3154 :
3155 724 : if (oprname == NULL)
3156 6 : break;
3157 :
3158 718 : appendStringInfo(&buffer, _("operator %s"), oprname);
3159 718 : break;
3160 : }
3161 :
3162 138 : case OperatorClassRelationId:
3163 : {
3164 : HeapTuple opcTup;
3165 : Form_pg_opclass opcForm;
3166 : HeapTuple amTup;
3167 : Form_pg_am amForm;
3168 : char *nspname;
3169 :
3170 138 : opcTup = SearchSysCache1(CLAOID,
3171 : ObjectIdGetDatum(object->objectId));
3172 138 : if (!HeapTupleIsValid(opcTup))
3173 : {
3174 6 : if (!missing_ok)
3175 0 : elog(ERROR, "cache lookup failed for opclass %u",
3176 : object->objectId);
3177 6 : break;
3178 : }
3179 :
3180 132 : opcForm = (Form_pg_opclass) GETSTRUCT(opcTup);
3181 :
3182 132 : amTup = SearchSysCache1(AMOID,
3183 : ObjectIdGetDatum(opcForm->opcmethod));
3184 132 : if (!HeapTupleIsValid(amTup))
3185 0 : elog(ERROR, "cache lookup failed for access method %u",
3186 : opcForm->opcmethod);
3187 132 : amForm = (Form_pg_am) GETSTRUCT(amTup);
3188 :
3189 : /* Qualify the name if not visible in search path */
3190 132 : if (OpclassIsVisible(object->objectId))
3191 104 : nspname = NULL;
3192 : else
3193 28 : nspname = get_namespace_name(opcForm->opcnamespace);
3194 :
3195 132 : appendStringInfo(&buffer, _("operator class %s for access method %s"),
3196 : quote_qualified_identifier(nspname,
3197 132 : NameStr(opcForm->opcname)),
3198 132 : NameStr(amForm->amname));
3199 :
3200 132 : ReleaseSysCache(amTup);
3201 132 : ReleaseSysCache(opcTup);
3202 132 : break;
3203 : }
3204 :
3205 140 : case OperatorFamilyRelationId:
3206 140 : getOpFamilyDescription(&buffer, object->objectId, missing_ok);
3207 140 : break;
3208 :
3209 68 : case AccessMethodRelationId:
3210 : {
3211 : HeapTuple tup;
3212 :
3213 68 : tup = SearchSysCache1(AMOID,
3214 : ObjectIdGetDatum(object->objectId));
3215 68 : if (!HeapTupleIsValid(tup))
3216 : {
3217 6 : if (!missing_ok)
3218 0 : elog(ERROR, "cache lookup failed for access method %u",
3219 : object->objectId);
3220 6 : break;
3221 : }
3222 :
3223 62 : appendStringInfo(&buffer, _("access method %s"),
3224 62 : NameStr(((Form_pg_am) GETSTRUCT(tup))->amname));
3225 62 : ReleaseSysCache(tup);
3226 62 : break;
3227 : }
3228 :
3229 962 : case AccessMethodOperatorRelationId:
3230 : {
3231 : Relation amopDesc;
3232 : HeapTuple tup;
3233 : ScanKeyData skey[1];
3234 : SysScanDesc amscan;
3235 : Form_pg_amop amopForm;
3236 : StringInfoData opfam;
3237 :
3238 962 : amopDesc = table_open(AccessMethodOperatorRelationId,
3239 : AccessShareLock);
3240 :
3241 962 : ScanKeyInit(&skey[0],
3242 : Anum_pg_amop_oid,
3243 : BTEqualStrategyNumber, F_OIDEQ,
3244 : ObjectIdGetDatum(object->objectId));
3245 :
3246 962 : amscan = systable_beginscan(amopDesc, AccessMethodOperatorOidIndexId, true,
3247 : NULL, 1, skey);
3248 :
3249 962 : tup = systable_getnext(amscan);
3250 :
3251 962 : if (!HeapTupleIsValid(tup))
3252 : {
3253 6 : if (!missing_ok)
3254 0 : elog(ERROR, "could not find tuple for amop entry %u",
3255 : object->objectId);
3256 :
3257 6 : systable_endscan(amscan);
3258 6 : table_close(amopDesc, AccessShareLock);
3259 6 : break;
3260 : }
3261 :
3262 956 : amopForm = (Form_pg_amop) GETSTRUCT(tup);
3263 :
3264 956 : initStringInfo(&opfam);
3265 956 : getOpFamilyDescription(&opfam, amopForm->amopfamily, false);
3266 :
3267 : /*
3268 : * We use FORMAT_TYPE_ALLOW_INVALID here so as not to fail
3269 : * completely if the type links are dangling, which is a form
3270 : * of catalog corruption that could occur due to old bugs.
3271 : */
3272 :
3273 : /*------
3274 : translator: %d is the operator strategy (a number), the
3275 : first two %s's are data type names, the third %s is the
3276 : description of the operator family, and the last %s is the
3277 : textual form of the operator with arguments. */
3278 956 : appendStringInfo(&buffer, _("operator %d (%s, %s) of %s: %s"),
3279 956 : amopForm->amopstrategy,
3280 : format_type_extended(amopForm->amoplefttype,
3281 : -1, FORMAT_TYPE_ALLOW_INVALID),
3282 : format_type_extended(amopForm->amoprighttype,
3283 : -1, FORMAT_TYPE_ALLOW_INVALID),
3284 : opfam.data,
3285 : format_operator(amopForm->amopopr));
3286 :
3287 956 : pfree(opfam.data);
3288 :
3289 956 : systable_endscan(amscan);
3290 956 : table_close(amopDesc, AccessShareLock);
3291 956 : break;
3292 : }
3293 :
3294 356 : case AccessMethodProcedureRelationId:
3295 : {
3296 : Relation amprocDesc;
3297 : ScanKeyData skey[1];
3298 : SysScanDesc amscan;
3299 : HeapTuple tup;
3300 : Form_pg_amproc amprocForm;
3301 : StringInfoData opfam;
3302 :
3303 356 : amprocDesc = table_open(AccessMethodProcedureRelationId,
3304 : AccessShareLock);
3305 :
3306 356 : ScanKeyInit(&skey[0],
3307 : Anum_pg_amproc_oid,
3308 : BTEqualStrategyNumber, F_OIDEQ,
3309 : ObjectIdGetDatum(object->objectId));
3310 :
3311 356 : amscan = systable_beginscan(amprocDesc, AccessMethodProcedureOidIndexId, true,
3312 : NULL, 1, skey);
3313 :
3314 356 : tup = systable_getnext(amscan);
3315 :
3316 356 : if (!HeapTupleIsValid(tup))
3317 : {
3318 6 : if (!missing_ok)
3319 0 : elog(ERROR, "could not find tuple for amproc entry %u",
3320 : object->objectId);
3321 :
3322 6 : systable_endscan(amscan);
3323 6 : table_close(amprocDesc, AccessShareLock);
3324 6 : break;
3325 : }
3326 :
3327 350 : amprocForm = (Form_pg_amproc) GETSTRUCT(tup);
3328 :
3329 350 : initStringInfo(&opfam);
3330 350 : getOpFamilyDescription(&opfam, amprocForm->amprocfamily, false);
3331 :
3332 : /*
3333 : * We use FORMAT_TYPE_ALLOW_INVALID here so as not to fail
3334 : * completely if the type links are dangling, which is a form
3335 : * of catalog corruption that could occur due to old bugs.
3336 : */
3337 :
3338 : /*------
3339 : translator: %d is the function number, the first two %s's
3340 : are data type names, the third %s is the description of the
3341 : operator family, and the last %s is the textual form of the
3342 : function with arguments. */
3343 350 : appendStringInfo(&buffer, _("function %d (%s, %s) of %s: %s"),
3344 350 : amprocForm->amprocnum,
3345 : format_type_extended(amprocForm->amproclefttype,
3346 : -1, FORMAT_TYPE_ALLOW_INVALID),
3347 : format_type_extended(amprocForm->amprocrighttype,
3348 : -1, FORMAT_TYPE_ALLOW_INVALID),
3349 : opfam.data,
3350 : format_procedure(amprocForm->amproc));
3351 :
3352 350 : pfree(opfam.data);
3353 :
3354 350 : systable_endscan(amscan);
3355 350 : table_close(amprocDesc, AccessShareLock);
3356 350 : break;
3357 : }
3358 :
3359 2674 : case RewriteRelationId:
3360 : {
3361 : Relation ruleDesc;
3362 : ScanKeyData skey[1];
3363 : SysScanDesc rcscan;
3364 : HeapTuple tup;
3365 : Form_pg_rewrite rule;
3366 : StringInfoData rel;
3367 :
3368 2674 : ruleDesc = table_open(RewriteRelationId, AccessShareLock);
3369 :
3370 2674 : ScanKeyInit(&skey[0],
3371 : Anum_pg_rewrite_oid,
3372 : BTEqualStrategyNumber, F_OIDEQ,
3373 : ObjectIdGetDatum(object->objectId));
3374 :
3375 2674 : rcscan = systable_beginscan(ruleDesc, RewriteOidIndexId, true,
3376 : NULL, 1, skey);
3377 :
3378 2674 : tup = systable_getnext(rcscan);
3379 :
3380 2674 : if (!HeapTupleIsValid(tup))
3381 : {
3382 6 : if (!missing_ok)
3383 0 : elog(ERROR, "could not find tuple for rule %u",
3384 : object->objectId);
3385 :
3386 6 : systable_endscan(rcscan);
3387 6 : table_close(ruleDesc, AccessShareLock);
3388 6 : break;
3389 : }
3390 :
3391 2668 : rule = (Form_pg_rewrite) GETSTRUCT(tup);
3392 :
3393 2668 : initStringInfo(&rel);
3394 2668 : getRelationDescription(&rel, rule->ev_class, false);
3395 :
3396 : /* translator: second %s is, e.g., "table %s" */
3397 2668 : appendStringInfo(&buffer, _("rule %s on %s"),
3398 2668 : NameStr(rule->rulename), rel.data);
3399 2668 : pfree(rel.data);
3400 2668 : systable_endscan(rcscan);
3401 2668 : table_close(ruleDesc, AccessShareLock);
3402 2668 : break;
3403 : }
3404 :
3405 12782 : case TriggerRelationId:
3406 : {
3407 : Relation trigDesc;
3408 : ScanKeyData skey[1];
3409 : SysScanDesc tgscan;
3410 : HeapTuple tup;
3411 : Form_pg_trigger trig;
3412 : StringInfoData rel;
3413 :
3414 12782 : trigDesc = table_open(TriggerRelationId, AccessShareLock);
3415 :
3416 12782 : ScanKeyInit(&skey[0],
3417 : Anum_pg_trigger_oid,
3418 : BTEqualStrategyNumber, F_OIDEQ,
3419 : ObjectIdGetDatum(object->objectId));
3420 :
3421 12782 : tgscan = systable_beginscan(trigDesc, TriggerOidIndexId, true,
3422 : NULL, 1, skey);
3423 :
3424 12782 : tup = systable_getnext(tgscan);
3425 :
3426 12782 : if (!HeapTupleIsValid(tup))
3427 : {
3428 6 : if (!missing_ok)
3429 0 : elog(ERROR, "could not find tuple for trigger %u",
3430 : object->objectId);
3431 :
3432 6 : systable_endscan(tgscan);
3433 6 : table_close(trigDesc, AccessShareLock);
3434 6 : break;
3435 : }
3436 :
3437 12776 : trig = (Form_pg_trigger) GETSTRUCT(tup);
3438 :
3439 12776 : initStringInfo(&rel);
3440 12776 : getRelationDescription(&rel, trig->tgrelid, false);
3441 :
3442 : /* translator: second %s is, e.g., "table %s" */
3443 12776 : appendStringInfo(&buffer, _("trigger %s on %s"),
3444 12776 : NameStr(trig->tgname), rel.data);
3445 12776 : pfree(rel.data);
3446 12776 : systable_endscan(tgscan);
3447 12776 : table_close(trigDesc, AccessShareLock);
3448 12776 : break;
3449 : }
3450 :
3451 152 : case NamespaceRelationId:
3452 : {
3453 : char *nspname;
3454 :
3455 152 : nspname = get_namespace_name(object->objectId);
3456 152 : if (!nspname)
3457 : {
3458 6 : if (!missing_ok)
3459 0 : elog(ERROR, "cache lookup failed for namespace %u",
3460 : object->objectId);
3461 6 : break;
3462 : }
3463 146 : appendStringInfo(&buffer, _("schema %s"), nspname);
3464 146 : break;
3465 : }
3466 :
3467 346 : case StatisticExtRelationId:
3468 : {
3469 : HeapTuple stxTup;
3470 : Form_pg_statistic_ext stxForm;
3471 : char *nspname;
3472 :
3473 346 : stxTup = SearchSysCache1(STATEXTOID,
3474 : ObjectIdGetDatum(object->objectId));
3475 346 : if (!HeapTupleIsValid(stxTup))
3476 : {
3477 6 : if (!missing_ok)
3478 0 : elog(ERROR, "could not find tuple for statistics object %u",
3479 : object->objectId);
3480 6 : break;
3481 : }
3482 :
3483 340 : stxForm = (Form_pg_statistic_ext) GETSTRUCT(stxTup);
3484 :
3485 : /* Qualify the name if not visible in search path */
3486 340 : if (StatisticsObjIsVisible(object->objectId))
3487 292 : nspname = NULL;
3488 : else
3489 48 : nspname = get_namespace_name(stxForm->stxnamespace);
3490 :
3491 340 : appendStringInfo(&buffer, _("statistics object %s"),
3492 : quote_qualified_identifier(nspname,
3493 340 : NameStr(stxForm->stxname)));
3494 :
3495 340 : ReleaseSysCache(stxTup);
3496 340 : break;
3497 : }
3498 :
3499 36 : case TSParserRelationId:
3500 : {
3501 : HeapTuple tup;
3502 : Form_pg_ts_parser prsForm;
3503 : char *nspname;
3504 :
3505 36 : tup = SearchSysCache1(TSPARSEROID,
3506 : ObjectIdGetDatum(object->objectId));
3507 36 : if (!HeapTupleIsValid(tup))
3508 : {
3509 6 : if (!missing_ok)
3510 0 : elog(ERROR, "cache lookup failed for text search parser %u",
3511 : object->objectId);
3512 6 : break;
3513 : }
3514 30 : prsForm = (Form_pg_ts_parser) GETSTRUCT(tup);
3515 :
3516 : /* Qualify the name if not visible in search path */
3517 30 : if (TSParserIsVisible(object->objectId))
3518 18 : nspname = NULL;
3519 : else
3520 12 : nspname = get_namespace_name(prsForm->prsnamespace);
3521 :
3522 30 : appendStringInfo(&buffer, _("text search parser %s"),
3523 : quote_qualified_identifier(nspname,
3524 30 : NameStr(prsForm->prsname)));
3525 30 : ReleaseSysCache(tup);
3526 30 : break;
3527 : }
3528 :
3529 42 : case TSDictionaryRelationId:
3530 : {
3531 : HeapTuple tup;
3532 : Form_pg_ts_dict dictForm;
3533 : char *nspname;
3534 :
3535 42 : tup = SearchSysCache1(TSDICTOID,
3536 : ObjectIdGetDatum(object->objectId));
3537 42 : if (!HeapTupleIsValid(tup))
3538 : {
3539 6 : if (!missing_ok)
3540 0 : elog(ERROR, "cache lookup failed for text search dictionary %u",
3541 : object->objectId);
3542 6 : break;
3543 : }
3544 :
3545 36 : dictForm = (Form_pg_ts_dict) GETSTRUCT(tup);
3546 :
3547 : /* Qualify the name if not visible in search path */
3548 36 : if (TSDictionaryIsVisible(object->objectId))
3549 24 : nspname = NULL;
3550 : else
3551 12 : nspname = get_namespace_name(dictForm->dictnamespace);
3552 :
3553 36 : appendStringInfo(&buffer, _("text search dictionary %s"),
3554 : quote_qualified_identifier(nspname,
3555 36 : NameStr(dictForm->dictname)));
3556 36 : ReleaseSysCache(tup);
3557 36 : break;
3558 : }
3559 :
3560 36 : case TSTemplateRelationId:
3561 : {
3562 : HeapTuple tup;
3563 : Form_pg_ts_template tmplForm;
3564 : char *nspname;
3565 :
3566 36 : tup = SearchSysCache1(TSTEMPLATEOID,
3567 : ObjectIdGetDatum(object->objectId));
3568 36 : if (!HeapTupleIsValid(tup))
3569 : {
3570 6 : if (!missing_ok)
3571 0 : elog(ERROR, "cache lookup failed for text search template %u",
3572 : object->objectId);
3573 6 : break;
3574 : }
3575 :
3576 30 : tmplForm = (Form_pg_ts_template) GETSTRUCT(tup);
3577 :
3578 : /* Qualify the name if not visible in search path */
3579 30 : if (TSTemplateIsVisible(object->objectId))
3580 18 : nspname = NULL;
3581 : else
3582 12 : nspname = get_namespace_name(tmplForm->tmplnamespace);
3583 :
3584 30 : appendStringInfo(&buffer, _("text search template %s"),
3585 : quote_qualified_identifier(nspname,
3586 30 : NameStr(tmplForm->tmplname)));
3587 30 : ReleaseSysCache(tup);
3588 30 : break;
3589 : }
3590 :
3591 42 : case TSConfigRelationId:
3592 : {
3593 : HeapTuple tup;
3594 : Form_pg_ts_config cfgForm;
3595 : char *nspname;
3596 :
3597 42 : tup = SearchSysCache1(TSCONFIGOID,
3598 : ObjectIdGetDatum(object->objectId));
3599 42 : if (!HeapTupleIsValid(tup))
3600 : {
3601 6 : if (!missing_ok)
3602 0 : elog(ERROR, "cache lookup failed for text search configuration %u",
3603 : object->objectId);
3604 6 : break;
3605 : }
3606 :
3607 36 : cfgForm = (Form_pg_ts_config) GETSTRUCT(tup);
3608 :
3609 : /* Qualify the name if not visible in search path */
3610 36 : if (TSConfigIsVisible(object->objectId))
3611 24 : nspname = NULL;
3612 : else
3613 12 : nspname = get_namespace_name(cfgForm->cfgnamespace);
3614 :
3615 36 : appendStringInfo(&buffer, _("text search configuration %s"),
3616 : quote_qualified_identifier(nspname,
3617 36 : NameStr(cfgForm->cfgname)));
3618 36 : ReleaseSysCache(tup);
3619 36 : break;
3620 : }
3621 :
3622 166 : case AuthIdRelationId:
3623 : {
3624 166 : char *username = GetUserNameFromId(object->objectId,
3625 : missing_ok);
3626 :
3627 166 : if (username)
3628 160 : appendStringInfo(&buffer, _("role %s"), username);
3629 166 : break;
3630 : }
3631 :
3632 54 : case AuthMemRelationId:
3633 : {
3634 : Relation amDesc;
3635 : ScanKeyData skey[1];
3636 : SysScanDesc rcscan;
3637 : HeapTuple tup;
3638 : Form_pg_auth_members amForm;
3639 :
3640 54 : amDesc = table_open(AuthMemRelationId, AccessShareLock);
3641 :
3642 54 : ScanKeyInit(&skey[0],
3643 : Anum_pg_auth_members_oid,
3644 : BTEqualStrategyNumber, F_OIDEQ,
3645 : ObjectIdGetDatum(object->objectId));
3646 :
3647 54 : rcscan = systable_beginscan(amDesc, AuthMemOidIndexId, true,
3648 : NULL, 1, skey);
3649 :
3650 54 : tup = systable_getnext(rcscan);
3651 :
3652 54 : if (!HeapTupleIsValid(tup))
3653 : {
3654 6 : if (!missing_ok)
3655 0 : elog(ERROR, "could not find tuple for role membership %u",
3656 : object->objectId);
3657 :
3658 6 : systable_endscan(rcscan);
3659 6 : table_close(amDesc, AccessShareLock);
3660 6 : break;
3661 : }
3662 :
3663 48 : amForm = (Form_pg_auth_members) GETSTRUCT(tup);
3664 :
3665 48 : appendStringInfo(&buffer, _("membership of role %s in role %s"),
3666 : GetUserNameFromId(amForm->member, false),
3667 : GetUserNameFromId(amForm->roleid, false));
3668 :
3669 48 : systable_endscan(rcscan);
3670 48 : table_close(amDesc, AccessShareLock);
3671 48 : break;
3672 : }
3673 :
3674 18 : case DatabaseRelationId:
3675 : {
3676 : char *datname;
3677 :
3678 18 : datname = get_database_name(object->objectId);
3679 18 : if (!datname)
3680 : {
3681 6 : if (!missing_ok)
3682 0 : elog(ERROR, "cache lookup failed for database %u",
3683 : object->objectId);
3684 6 : break;
3685 : }
3686 12 : appendStringInfo(&buffer, _("database %s"), datname);
3687 12 : break;
3688 : }
3689 :
3690 6 : case TableSpaceRelationId:
3691 : {
3692 : char *tblspace;
3693 :
3694 6 : tblspace = get_tablespace_name(object->objectId);
3695 6 : if (!tblspace)
3696 : {
3697 6 : if (!missing_ok)
3698 0 : elog(ERROR, "cache lookup failed for tablespace %u",
3699 : object->objectId);
3700 6 : break;
3701 : }
3702 0 : appendStringInfo(&buffer, _("tablespace %s"), tblspace);
3703 0 : break;
3704 : }
3705 :
3706 74 : case ForeignDataWrapperRelationId:
3707 : {
3708 : ForeignDataWrapper *fdw;
3709 :
3710 74 : fdw = GetForeignDataWrapperExtended(object->objectId,
3711 : missing_ok);
3712 74 : if (fdw)
3713 68 : appendStringInfo(&buffer, _("foreign-data wrapper %s"), fdw->fdwname);
3714 74 : break;
3715 : }
3716 :
3717 136 : case ForeignServerRelationId:
3718 : {
3719 : ForeignServer *srv;
3720 :
3721 136 : srv = GetForeignServerExtended(object->objectId, missing_ok);
3722 136 : if (srv)
3723 130 : appendStringInfo(&buffer, _("server %s"), srv->servername);
3724 136 : break;
3725 : }
3726 :
3727 132 : case UserMappingRelationId:
3728 : {
3729 : HeapTuple tup;
3730 : Oid useid;
3731 : char *usename;
3732 : Form_pg_user_mapping umform;
3733 : ForeignServer *srv;
3734 :
3735 132 : tup = SearchSysCache1(USERMAPPINGOID,
3736 : ObjectIdGetDatum(object->objectId));
3737 132 : if (!HeapTupleIsValid(tup))
3738 : {
3739 6 : if (!missing_ok)
3740 0 : elog(ERROR, "cache lookup failed for user mapping %u",
3741 : object->objectId);
3742 6 : break;
3743 : }
3744 :
3745 126 : umform = (Form_pg_user_mapping) GETSTRUCT(tup);
3746 126 : useid = umform->umuser;
3747 126 : srv = GetForeignServer(umform->umserver);
3748 :
3749 126 : ReleaseSysCache(tup);
3750 :
3751 126 : if (OidIsValid(useid))
3752 100 : usename = GetUserNameFromId(useid, false);
3753 : else
3754 26 : usename = "public";
3755 :
3756 126 : appendStringInfo(&buffer, _("user mapping for %s on server %s"), usename,
3757 : srv->servername);
3758 126 : break;
3759 : }
3760 :
3761 48 : case DefaultAclRelationId:
3762 : {
3763 : Relation defaclrel;
3764 : ScanKeyData skey[1];
3765 : SysScanDesc rcscan;
3766 : HeapTuple tup;
3767 : Form_pg_default_acl defacl;
3768 : char *rolename;
3769 : char *nspname;
3770 :
3771 48 : defaclrel = table_open(DefaultAclRelationId, AccessShareLock);
3772 :
3773 48 : ScanKeyInit(&skey[0],
3774 : Anum_pg_default_acl_oid,
3775 : BTEqualStrategyNumber, F_OIDEQ,
3776 : ObjectIdGetDatum(object->objectId));
3777 :
3778 48 : rcscan = systable_beginscan(defaclrel, DefaultAclOidIndexId,
3779 : true, NULL, 1, skey);
3780 :
3781 48 : tup = systable_getnext(rcscan);
3782 :
3783 48 : if (!HeapTupleIsValid(tup))
3784 : {
3785 6 : if (!missing_ok)
3786 0 : elog(ERROR, "could not find tuple for default ACL %u",
3787 : object->objectId);
3788 :
3789 6 : systable_endscan(rcscan);
3790 6 : table_close(defaclrel, AccessShareLock);
3791 6 : break;
3792 : }
3793 :
3794 42 : defacl = (Form_pg_default_acl) GETSTRUCT(tup);
3795 :
3796 42 : rolename = GetUserNameFromId(defacl->defaclrole, false);
3797 :
3798 42 : if (OidIsValid(defacl->defaclnamespace))
3799 30 : nspname = get_namespace_name(defacl->defaclnamespace);
3800 : else
3801 12 : nspname = NULL;
3802 :
3803 42 : switch (defacl->defaclobjtype)
3804 : {
3805 30 : case DEFACLOBJ_RELATION:
3806 30 : if (nspname)
3807 18 : appendStringInfo(&buffer,
3808 18 : _("default privileges on new relations belonging to role %s in schema %s"),
3809 : rolename, nspname);
3810 : else
3811 12 : appendStringInfo(&buffer,
3812 12 : _("default privileges on new relations belonging to role %s"),
3813 : rolename);
3814 30 : break;
3815 0 : case DEFACLOBJ_SEQUENCE:
3816 0 : if (nspname)
3817 0 : appendStringInfo(&buffer,
3818 0 : _("default privileges on new sequences belonging to role %s in schema %s"),
3819 : rolename, nspname);
3820 : else
3821 0 : appendStringInfo(&buffer,
3822 0 : _("default privileges on new sequences belonging to role %s"),
3823 : rolename);
3824 0 : break;
3825 6 : case DEFACLOBJ_FUNCTION:
3826 6 : if (nspname)
3827 6 : appendStringInfo(&buffer,
3828 6 : _("default privileges on new functions belonging to role %s in schema %s"),
3829 : rolename, nspname);
3830 : else
3831 0 : appendStringInfo(&buffer,
3832 0 : _("default privileges on new functions belonging to role %s"),
3833 : rolename);
3834 6 : break;
3835 6 : case DEFACLOBJ_TYPE:
3836 6 : if (nspname)
3837 6 : appendStringInfo(&buffer,
3838 6 : _("default privileges on new types belonging to role %s in schema %s"),
3839 : rolename, nspname);
3840 : else
3841 0 : appendStringInfo(&buffer,
3842 0 : _("default privileges on new types belonging to role %s"),
3843 : rolename);
3844 6 : break;
3845 0 : case DEFACLOBJ_NAMESPACE:
3846 : Assert(!nspname);
3847 0 : appendStringInfo(&buffer,
3848 0 : _("default privileges on new schemas belonging to role %s"),
3849 : rolename);
3850 0 : break;
3851 0 : case DEFACLOBJ_LARGEOBJECT:
3852 : Assert(!nspname);
3853 0 : appendStringInfo(&buffer,
3854 0 : _("default privileges on new large objects belonging to role %s"),
3855 : rolename);
3856 0 : break;
3857 0 : default:
3858 : /* shouldn't get here */
3859 0 : if (nspname)
3860 0 : appendStringInfo(&buffer,
3861 0 : _("default privileges belonging to role %s in schema %s"),
3862 : rolename, nspname);
3863 : else
3864 0 : appendStringInfo(&buffer,
3865 0 : _("default privileges belonging to role %s"),
3866 : rolename);
3867 0 : break;
3868 : }
3869 :
3870 42 : systable_endscan(rcscan);
3871 42 : table_close(defaclrel, AccessShareLock);
3872 42 : break;
3873 : }
3874 :
3875 58 : case ExtensionRelationId:
3876 : {
3877 : char *extname;
3878 :
3879 58 : extname = get_extension_name(object->objectId);
3880 58 : if (!extname)
3881 : {
3882 6 : if (!missing_ok)
3883 0 : elog(ERROR, "cache lookup failed for extension %u",
3884 : object->objectId);
3885 6 : break;
3886 : }
3887 52 : appendStringInfo(&buffer, _("extension %s"), extname);
3888 52 : break;
3889 : }
3890 :
3891 38 : case EventTriggerRelationId:
3892 : {
3893 : HeapTuple tup;
3894 :
3895 38 : tup = SearchSysCache1(EVENTTRIGGEROID,
3896 : ObjectIdGetDatum(object->objectId));
3897 38 : if (!HeapTupleIsValid(tup))
3898 : {
3899 6 : if (!missing_ok)
3900 0 : elog(ERROR, "cache lookup failed for event trigger %u",
3901 : object->objectId);
3902 6 : break;
3903 : }
3904 32 : appendStringInfo(&buffer, _("event trigger %s"),
3905 32 : NameStr(((Form_pg_event_trigger) GETSTRUCT(tup))->evtname));
3906 32 : ReleaseSysCache(tup);
3907 32 : break;
3908 : }
3909 :
3910 128 : case ParameterAclRelationId:
3911 : {
3912 : HeapTuple tup;
3913 : Datum nameDatum;
3914 : char *parname;
3915 :
3916 128 : tup = SearchSysCache1(PARAMETERACLOID,
3917 : ObjectIdGetDatum(object->objectId));
3918 128 : if (!HeapTupleIsValid(tup))
3919 : {
3920 6 : if (!missing_ok)
3921 0 : elog(ERROR, "cache lookup failed for parameter ACL %u",
3922 : object->objectId);
3923 6 : break;
3924 : }
3925 122 : nameDatum = SysCacheGetAttrNotNull(PARAMETERACLOID, tup,
3926 : Anum_pg_parameter_acl_parname);
3927 122 : parname = TextDatumGetCString(nameDatum);
3928 122 : appendStringInfo(&buffer, _("parameter %s"), parname);
3929 122 : ReleaseSysCache(tup);
3930 122 : break;
3931 : }
3932 :
3933 448 : case PolicyRelationId:
3934 : {
3935 : Relation policy_rel;
3936 : ScanKeyData skey[1];
3937 : SysScanDesc sscan;
3938 : HeapTuple tuple;
3939 : Form_pg_policy form_policy;
3940 : StringInfoData rel;
3941 :
3942 448 : policy_rel = table_open(PolicyRelationId, AccessShareLock);
3943 :
3944 448 : ScanKeyInit(&skey[0],
3945 : Anum_pg_policy_oid,
3946 : BTEqualStrategyNumber, F_OIDEQ,
3947 : ObjectIdGetDatum(object->objectId));
3948 :
3949 448 : sscan = systable_beginscan(policy_rel, PolicyOidIndexId,
3950 : true, NULL, 1, skey);
3951 :
3952 448 : tuple = systable_getnext(sscan);
3953 :
3954 448 : if (!HeapTupleIsValid(tuple))
3955 : {
3956 6 : if (!missing_ok)
3957 0 : elog(ERROR, "could not find tuple for policy %u",
3958 : object->objectId);
3959 :
3960 6 : systable_endscan(sscan);
3961 6 : table_close(policy_rel, AccessShareLock);
3962 6 : break;
3963 : }
3964 :
3965 442 : form_policy = (Form_pg_policy) GETSTRUCT(tuple);
3966 :
3967 442 : initStringInfo(&rel);
3968 442 : getRelationDescription(&rel, form_policy->polrelid, false);
3969 :
3970 : /* translator: second %s is, e.g., "table %s" */
3971 442 : appendStringInfo(&buffer, _("policy %s on %s"),
3972 442 : NameStr(form_policy->polname), rel.data);
3973 442 : pfree(rel.data);
3974 442 : systable_endscan(sscan);
3975 442 : table_close(policy_rel, AccessShareLock);
3976 442 : break;
3977 : }
3978 :
3979 6 : case PublicationRelationId:
3980 : {
3981 6 : char *pubname = get_publication_name(object->objectId,
3982 : missing_ok);
3983 :
3984 6 : if (pubname)
3985 0 : appendStringInfo(&buffer, _("publication %s"), pubname);
3986 6 : break;
3987 : }
3988 :
3989 148 : case PublicationNamespaceRelationId:
3990 : {
3991 : char *pubname;
3992 : char *nspname;
3993 :
3994 148 : if (!getPublicationSchemaInfo(object, missing_ok,
3995 : &pubname, &nspname))
3996 6 : break;
3997 :
3998 142 : appendStringInfo(&buffer, _("publication of schema %s in publication %s"),
3999 : nspname, pubname);
4000 142 : pfree(pubname);
4001 142 : pfree(nspname);
4002 142 : break;
4003 : }
4004 :
4005 394 : case PublicationRelRelationId:
4006 : {
4007 : HeapTuple tup;
4008 : char *pubname;
4009 : Form_pg_publication_rel prform;
4010 : StringInfoData rel;
4011 :
4012 394 : tup = SearchSysCache1(PUBLICATIONREL,
4013 : ObjectIdGetDatum(object->objectId));
4014 394 : if (!HeapTupleIsValid(tup))
4015 : {
4016 6 : if (!missing_ok)
4017 0 : elog(ERROR, "cache lookup failed for publication table %u",
4018 : object->objectId);
4019 6 : break;
4020 : }
4021 :
4022 388 : prform = (Form_pg_publication_rel) GETSTRUCT(tup);
4023 388 : pubname = get_publication_name(prform->prpubid, false);
4024 :
4025 388 : initStringInfo(&rel);
4026 388 : getRelationDescription(&rel, prform->prrelid, false);
4027 :
4028 : /* translator: first %s is, e.g., "table %s" */
4029 388 : appendStringInfo(&buffer, _("publication of %s in publication %s"),
4030 : rel.data, pubname);
4031 388 : pfree(rel.data);
4032 388 : ReleaseSysCache(tup);
4033 388 : break;
4034 : }
4035 :
4036 6 : case SubscriptionRelationId:
4037 : {
4038 6 : char *subname = get_subscription_name(object->objectId,
4039 : missing_ok);
4040 :
4041 6 : if (subname)
4042 0 : appendStringInfo(&buffer, _("subscription %s"), subname);
4043 6 : break;
4044 : }
4045 :
4046 24 : case TransformRelationId:
4047 : {
4048 : HeapTuple trfTup;
4049 : Form_pg_transform trfForm;
4050 :
4051 24 : trfTup = SearchSysCache1(TRFOID,
4052 : ObjectIdGetDatum(object->objectId));
4053 24 : if (!HeapTupleIsValid(trfTup))
4054 : {
4055 6 : if (!missing_ok)
4056 0 : elog(ERROR, "could not find tuple for transform %u",
4057 : object->objectId);
4058 6 : break;
4059 : }
4060 :
4061 18 : trfForm = (Form_pg_transform) GETSTRUCT(trfTup);
4062 :
4063 18 : appendStringInfo(&buffer, _("transform for %s language %s"),
4064 : format_type_be(trfForm->trftype),
4065 : get_language_name(trfForm->trflang, false));
4066 :
4067 18 : ReleaseSysCache(trfTup);
4068 18 : break;
4069 : }
4070 :
4071 0 : default:
4072 0 : elog(ERROR, "unsupported object class: %u", object->classId);
4073 : }
4074 :
4075 : /* an empty buffer is equivalent to no object found */
4076 172534 : if (buffer.len == 0)
4077 252 : return NULL;
4078 :
4079 172282 : return buffer.data;
4080 : }
4081 :
4082 : /*
4083 : * getObjectDescriptionOids: as above, except the object is specified by Oids
4084 : */
4085 : char *
4086 0 : getObjectDescriptionOids(Oid classid, Oid objid)
4087 : {
4088 : ObjectAddress address;
4089 :
4090 0 : address.classId = classid;
4091 0 : address.objectId = objid;
4092 0 : address.objectSubId = 0;
4093 :
4094 0 : return getObjectDescription(&address, false);
4095 : }
4096 :
4097 : /*
4098 : * subroutine for getObjectDescription: describe a relation
4099 : *
4100 : * The result is appended to "buffer".
4101 : */
4102 : static void
4103 89954 : getRelationDescription(StringInfo buffer, Oid relid, bool missing_ok)
4104 : {
4105 : HeapTuple relTup;
4106 : Form_pg_class relForm;
4107 : char *nspname;
4108 : char *relname;
4109 :
4110 89954 : relTup = SearchSysCache1(RELOID,
4111 : ObjectIdGetDatum(relid));
4112 89954 : if (!HeapTupleIsValid(relTup))
4113 : {
4114 6 : if (!missing_ok)
4115 0 : elog(ERROR, "cache lookup failed for relation %u", relid);
4116 6 : return;
4117 : }
4118 89948 : relForm = (Form_pg_class) GETSTRUCT(relTup);
4119 :
4120 : /* Qualify the name if not visible in search path */
4121 89948 : if (RelationIsVisible(relid))
4122 63058 : nspname = NULL;
4123 : else
4124 26890 : nspname = get_namespace_name(relForm->relnamespace);
4125 :
4126 89948 : relname = quote_qualified_identifier(nspname, NameStr(relForm->relname));
4127 :
4128 89948 : switch (relForm->relkind)
4129 : {
4130 49590 : case RELKIND_RELATION:
4131 : case RELKIND_PARTITIONED_TABLE:
4132 49590 : appendStringInfo(buffer, _("table %s"),
4133 : relname);
4134 49590 : break;
4135 21272 : case RELKIND_INDEX:
4136 : case RELKIND_PARTITIONED_INDEX:
4137 21272 : appendStringInfo(buffer, _("index %s"),
4138 : relname);
4139 21272 : break;
4140 854 : case RELKIND_SEQUENCE:
4141 854 : appendStringInfo(buffer, _("sequence %s"),
4142 : relname);
4143 854 : break;
4144 9412 : case RELKIND_TOASTVALUE:
4145 9412 : appendStringInfo(buffer, _("toast table %s"),
4146 : relname);
4147 9412 : break;
4148 3546 : case RELKIND_VIEW:
4149 3546 : appendStringInfo(buffer, _("view %s"),
4150 : relname);
4151 3546 : break;
4152 596 : case RELKIND_MATVIEW:
4153 596 : appendStringInfo(buffer, _("materialized view %s"),
4154 : relname);
4155 596 : break;
4156 4272 : case RELKIND_COMPOSITE_TYPE:
4157 4272 : appendStringInfo(buffer, _("composite type %s"),
4158 : relname);
4159 4272 : break;
4160 406 : case RELKIND_FOREIGN_TABLE:
4161 406 : appendStringInfo(buffer, _("foreign table %s"),
4162 : relname);
4163 406 : break;
4164 0 : default:
4165 : /* shouldn't get here */
4166 0 : appendStringInfo(buffer, _("relation %s"),
4167 : relname);
4168 0 : break;
4169 : }
4170 :
4171 89948 : ReleaseSysCache(relTup);
4172 : }
4173 :
4174 : /*
4175 : * subroutine for getObjectDescription: describe an operator family
4176 : */
4177 : static void
4178 1446 : getOpFamilyDescription(StringInfo buffer, Oid opfid, bool missing_ok)
4179 : {
4180 : HeapTuple opfTup;
4181 : Form_pg_opfamily opfForm;
4182 : HeapTuple amTup;
4183 : Form_pg_am amForm;
4184 : char *nspname;
4185 :
4186 1446 : opfTup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfid));
4187 1446 : if (!HeapTupleIsValid(opfTup))
4188 : {
4189 6 : if (!missing_ok)
4190 0 : elog(ERROR, "cache lookup failed for opfamily %u", opfid);
4191 6 : return;
4192 : }
4193 1440 : opfForm = (Form_pg_opfamily) GETSTRUCT(opfTup);
4194 :
4195 1440 : amTup = SearchSysCache1(AMOID, ObjectIdGetDatum(opfForm->opfmethod));
4196 1440 : if (!HeapTupleIsValid(amTup))
4197 0 : elog(ERROR, "cache lookup failed for access method %u",
4198 : opfForm->opfmethod);
4199 1440 : amForm = (Form_pg_am) GETSTRUCT(amTup);
4200 :
4201 : /* Qualify the name if not visible in search path */
4202 1440 : if (OpfamilyIsVisible(opfid))
4203 1244 : nspname = NULL;
4204 : else
4205 196 : nspname = get_namespace_name(opfForm->opfnamespace);
4206 :
4207 1440 : appendStringInfo(buffer, _("operator family %s for access method %s"),
4208 : quote_qualified_identifier(nspname,
4209 1440 : NameStr(opfForm->opfname)),
4210 1440 : NameStr(amForm->amname));
4211 :
4212 1440 : ReleaseSysCache(amTup);
4213 1440 : ReleaseSysCache(opfTup);
4214 : }
4215 :
4216 : /*
4217 : * SQL-level callable version of getObjectDescription
4218 : */
4219 : Datum
4220 2136 : pg_describe_object(PG_FUNCTION_ARGS)
4221 : {
4222 2136 : Oid classid = PG_GETARG_OID(0);
4223 2136 : Oid objid = PG_GETARG_OID(1);
4224 2136 : int32 objsubid = PG_GETARG_INT32(2);
4225 : char *description;
4226 : ObjectAddress address;
4227 :
4228 : /* for "pinned" items in pg_depend, return null */
4229 2136 : if (!OidIsValid(classid) && !OidIsValid(objid))
4230 0 : PG_RETURN_NULL();
4231 :
4232 2136 : address.classId = classid;
4233 2136 : address.objectId = objid;
4234 2136 : address.objectSubId = objsubid;
4235 :
4236 2136 : description = getObjectDescription(&address, true);
4237 :
4238 2136 : if (description == NULL)
4239 252 : PG_RETURN_NULL();
4240 :
4241 1884 : PG_RETURN_TEXT_P(cstring_to_text(description));
4242 : }
4243 :
4244 : /*
4245 : * SQL-level callable function to obtain object type + identity
4246 : */
4247 : Datum
4248 2082 : pg_identify_object(PG_FUNCTION_ARGS)
4249 : {
4250 2082 : Oid classid = PG_GETARG_OID(0);
4251 2082 : Oid objid = PG_GETARG_OID(1);
4252 2082 : int32 objsubid = PG_GETARG_INT32(2);
4253 2082 : Oid schema_oid = InvalidOid;
4254 2082 : const char *objname = NULL;
4255 : char *objidentity;
4256 : ObjectAddress address;
4257 : Datum values[4];
4258 : bool nulls[4];
4259 : TupleDesc tupdesc;
4260 : HeapTuple htup;
4261 :
4262 2082 : address.classId = classid;
4263 2082 : address.objectId = objid;
4264 2082 : address.objectSubId = objsubid;
4265 :
4266 2082 : if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
4267 0 : elog(ERROR, "return type must be a row type");
4268 :
4269 2082 : if (is_objectclass_supported(address.classId))
4270 : {
4271 : HeapTuple objtup;
4272 1942 : Relation catalog = table_open(address.classId, AccessShareLock);
4273 :
4274 1942 : objtup = get_catalog_object_by_oid(catalog,
4275 1942 : get_object_attnum_oid(address.classId),
4276 : address.objectId);
4277 1942 : if (objtup != NULL)
4278 : {
4279 : bool isnull;
4280 : AttrNumber nspAttnum;
4281 : AttrNumber nameAttnum;
4282 :
4283 1726 : nspAttnum = get_object_attnum_namespace(address.classId);
4284 1726 : if (nspAttnum != InvalidAttrNumber)
4285 : {
4286 1058 : schema_oid = heap_getattr(objtup, nspAttnum,
4287 : RelationGetDescr(catalog), &isnull);
4288 1058 : if (isnull)
4289 0 : elog(ERROR, "invalid null namespace in object %u/%u/%d",
4290 : address.classId, address.objectId, address.objectSubId);
4291 : }
4292 :
4293 : /*
4294 : * We only return the object name if it can be used (together with
4295 : * the schema name, if any) as a unique identifier.
4296 : */
4297 1726 : if (get_object_namensp_unique(address.classId))
4298 : {
4299 1144 : nameAttnum = get_object_attnum_name(address.classId);
4300 1144 : if (nameAttnum != InvalidAttrNumber)
4301 : {
4302 : Datum nameDatum;
4303 :
4304 1144 : nameDatum = heap_getattr(objtup, nameAttnum,
4305 : RelationGetDescr(catalog), &isnull);
4306 1144 : if (isnull)
4307 0 : elog(ERROR, "invalid null name in object %u/%u/%d",
4308 : address.classId, address.objectId, address.objectSubId);
4309 1144 : objname = quote_identifier(NameStr(*(DatumGetName(nameDatum))));
4310 : }
4311 : }
4312 : }
4313 :
4314 1942 : table_close(catalog, AccessShareLock);
4315 : }
4316 :
4317 : /* object type, which can never be NULL */
4318 2082 : values[0] = CStringGetTextDatum(getObjectTypeDescription(&address, true));
4319 2082 : nulls[0] = false;
4320 :
4321 : /*
4322 : * Before doing anything, extract the object identity. If the identity
4323 : * could not be found, set all the fields except the object type to NULL.
4324 : */
4325 2082 : objidentity = getObjectIdentity(&address, true);
4326 :
4327 : /* schema name */
4328 2082 : if (OidIsValid(schema_oid) && objidentity)
4329 1052 : {
4330 1052 : const char *schema = quote_identifier(get_namespace_name(schema_oid));
4331 :
4332 1052 : values[1] = CStringGetTextDatum(schema);
4333 1052 : nulls[1] = false;
4334 : }
4335 : else
4336 1030 : nulls[1] = true;
4337 :
4338 : /* object name */
4339 2082 : if (objname && objidentity)
4340 : {
4341 1138 : values[2] = CStringGetTextDatum(objname);
4342 1138 : nulls[2] = false;
4343 : }
4344 : else
4345 944 : nulls[2] = true;
4346 :
4347 : /* object identity */
4348 2082 : if (objidentity)
4349 : {
4350 1830 : values[3] = CStringGetTextDatum(objidentity);
4351 1830 : nulls[3] = false;
4352 : }
4353 : else
4354 252 : nulls[3] = true;
4355 :
4356 2082 : htup = heap_form_tuple(tupdesc, values, nulls);
4357 :
4358 2082 : PG_RETURN_DATUM(HeapTupleGetDatum(htup));
4359 : }
4360 :
4361 : /*
4362 : * SQL-level callable function to obtain object type + identity
4363 : */
4364 : Datum
4365 572 : pg_identify_object_as_address(PG_FUNCTION_ARGS)
4366 : {
4367 572 : Oid classid = PG_GETARG_OID(0);
4368 572 : Oid objid = PG_GETARG_OID(1);
4369 572 : int32 objsubid = PG_GETARG_INT32(2);
4370 : ObjectAddress address;
4371 : char *identity;
4372 : List *names;
4373 : List *args;
4374 : Datum values[3];
4375 : bool nulls[3];
4376 : TupleDesc tupdesc;
4377 : HeapTuple htup;
4378 :
4379 572 : address.classId = classid;
4380 572 : address.objectId = objid;
4381 572 : address.objectSubId = objsubid;
4382 :
4383 572 : if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
4384 0 : elog(ERROR, "return type must be a row type");
4385 :
4386 : /* object type, which can never be NULL */
4387 572 : values[0] = CStringGetTextDatum(getObjectTypeDescription(&address, true));
4388 572 : nulls[0] = false;
4389 :
4390 : /* object identity */
4391 572 : identity = getObjectIdentityParts(&address, &names, &args, true);
4392 572 : if (identity == NULL)
4393 : {
4394 252 : nulls[1] = true;
4395 252 : nulls[2] = true;
4396 : }
4397 : else
4398 : {
4399 320 : pfree(identity);
4400 :
4401 : /* object_names */
4402 320 : if (names != NIL)
4403 320 : values[1] = PointerGetDatum(strlist_to_textarray(names));
4404 : else
4405 0 : values[1] = PointerGetDatum(construct_empty_array(TEXTOID));
4406 320 : nulls[1] = false;
4407 :
4408 : /* object_args */
4409 320 : if (args)
4410 84 : values[2] = PointerGetDatum(strlist_to_textarray(args));
4411 : else
4412 236 : values[2] = PointerGetDatum(construct_empty_array(TEXTOID));
4413 320 : nulls[2] = false;
4414 : }
4415 :
4416 572 : htup = heap_form_tuple(tupdesc, values, nulls);
4417 :
4418 572 : PG_RETURN_DATUM(HeapTupleGetDatum(htup));
4419 : }
4420 :
4421 : /*
4422 : * SQL-level callable function to obtain the ACL of a specified object, given
4423 : * its catalog OID, object OID and sub-object ID.
4424 : */
4425 : Datum
4426 78 : pg_get_acl(PG_FUNCTION_ARGS)
4427 : {
4428 78 : Oid classId = PG_GETARG_OID(0);
4429 78 : Oid objectId = PG_GETARG_OID(1);
4430 78 : int32 objsubid = PG_GETARG_INT32(2);
4431 : Oid catalogId;
4432 : AttrNumber Anum_acl;
4433 : Datum datum;
4434 : bool isnull;
4435 : HeapTuple tup;
4436 :
4437 : /* for "pinned" items in pg_depend, return null */
4438 78 : if (!OidIsValid(classId) && !OidIsValid(objectId))
4439 6 : PG_RETURN_NULL();
4440 :
4441 : /* for large objects, the catalog to look at is pg_largeobject_metadata */
4442 72 : catalogId = (classId == LargeObjectRelationId) ?
4443 72 : LargeObjectMetadataRelationId : classId;
4444 72 : Anum_acl = get_object_attnum_acl(catalogId);
4445 :
4446 : /* return NULL if no ACL field for this catalog */
4447 72 : if (Anum_acl == InvalidAttrNumber)
4448 0 : PG_RETURN_NULL();
4449 :
4450 : /*
4451 : * If dealing with a relation's attribute (objsubid is set), the ACL is
4452 : * retrieved from pg_attribute.
4453 : */
4454 72 : if (classId == RelationRelationId && objsubid != 0)
4455 48 : {
4456 48 : AttrNumber attnum = (AttrNumber) objsubid;
4457 :
4458 48 : tup = SearchSysCacheCopyAttNum(objectId, attnum);
4459 :
4460 48 : if (!HeapTupleIsValid(tup))
4461 0 : PG_RETURN_NULL();
4462 :
4463 48 : datum = SysCacheGetAttr(ATTNUM, tup, Anum_pg_attribute_attacl,
4464 : &isnull);
4465 : }
4466 : else
4467 : {
4468 : Relation rel;
4469 :
4470 24 : rel = table_open(catalogId, AccessShareLock);
4471 :
4472 24 : tup = get_catalog_object_by_oid(rel, get_object_attnum_oid(catalogId),
4473 : objectId);
4474 24 : if (!HeapTupleIsValid(tup))
4475 : {
4476 6 : table_close(rel, AccessShareLock);
4477 6 : PG_RETURN_NULL();
4478 : }
4479 :
4480 18 : datum = heap_getattr(tup, Anum_acl, RelationGetDescr(rel), &isnull);
4481 18 : table_close(rel, AccessShareLock);
4482 : }
4483 :
4484 66 : if (isnull)
4485 18 : PG_RETURN_NULL();
4486 :
4487 48 : PG_RETURN_DATUM(datum);
4488 : }
4489 :
4490 : /*
4491 : * Return a palloc'ed string that describes the type of object that the
4492 : * passed address is for.
4493 : *
4494 : * Keep ObjectTypeMap in sync with this.
4495 : */
4496 : char *
4497 6858 : getObjectTypeDescription(const ObjectAddress *object, bool missing_ok)
4498 : {
4499 : StringInfoData buffer;
4500 :
4501 6858 : initStringInfo(&buffer);
4502 :
4503 6858 : switch (object->classId)
4504 : {
4505 2098 : case RelationRelationId:
4506 2098 : getRelationTypeDescription(&buffer, object->objectId,
4507 : object->objectSubId,
4508 : missing_ok);
4509 2098 : break;
4510 :
4511 292 : case ProcedureRelationId:
4512 292 : getProcedureTypeDescription(&buffer, object->objectId,
4513 : missing_ok);
4514 292 : break;
4515 :
4516 1412 : case TypeRelationId:
4517 1412 : appendStringInfoString(&buffer, "type");
4518 1412 : break;
4519 :
4520 62 : case CastRelationId:
4521 62 : appendStringInfoString(&buffer, "cast");
4522 62 : break;
4523 :
4524 54 : case CollationRelationId:
4525 54 : appendStringInfoString(&buffer, "collation");
4526 54 : break;
4527 :
4528 564 : case ConstraintRelationId:
4529 564 : getConstraintTypeDescription(&buffer, object->objectId,
4530 : missing_ok);
4531 564 : break;
4532 :
4533 56 : case ConversionRelationId:
4534 56 : appendStringInfoString(&buffer, "conversion");
4535 56 : break;
4536 :
4537 440 : case AttrDefaultRelationId:
4538 440 : appendStringInfoString(&buffer, "default value");
4539 440 : break;
4540 :
4541 54 : case LanguageRelationId:
4542 54 : appendStringInfoString(&buffer, "language");
4543 54 : break;
4544 :
4545 12 : case LargeObjectRelationId:
4546 12 : appendStringInfoString(&buffer, "large object");
4547 12 : break;
4548 :
4549 58 : case OperatorRelationId:
4550 58 : appendStringInfoString(&buffer, "operator");
4551 58 : break;
4552 :
4553 62 : case OperatorClassRelationId:
4554 62 : appendStringInfoString(&buffer, "operator class");
4555 62 : break;
4556 :
4557 64 : case OperatorFamilyRelationId:
4558 64 : appendStringInfoString(&buffer, "operator family");
4559 64 : break;
4560 :
4561 54 : case AccessMethodRelationId:
4562 54 : appendStringInfoString(&buffer, "access method");
4563 54 : break;
4564 :
4565 54 : case AccessMethodOperatorRelationId:
4566 54 : appendStringInfoString(&buffer, "operator of access method");
4567 54 : break;
4568 :
4569 54 : case AccessMethodProcedureRelationId:
4570 54 : appendStringInfoString(&buffer, "function of access method");
4571 54 : break;
4572 :
4573 86 : case RewriteRelationId:
4574 86 : appendStringInfoString(&buffer, "rule");
4575 86 : break;
4576 :
4577 156 : case TriggerRelationId:
4578 156 : appendStringInfoString(&buffer, "trigger");
4579 156 : break;
4580 :
4581 136 : case NamespaceRelationId:
4582 136 : appendStringInfoString(&buffer, "schema");
4583 136 : break;
4584 :
4585 56 : case StatisticExtRelationId:
4586 56 : appendStringInfoString(&buffer, "statistics object");
4587 56 : break;
4588 :
4589 54 : case TSParserRelationId:
4590 54 : appendStringInfoString(&buffer, "text search parser");
4591 54 : break;
4592 :
4593 54 : case TSDictionaryRelationId:
4594 54 : appendStringInfoString(&buffer, "text search dictionary");
4595 54 : break;
4596 :
4597 54 : case TSTemplateRelationId:
4598 54 : appendStringInfoString(&buffer, "text search template");
4599 54 : break;
4600 :
4601 58 : case TSConfigRelationId:
4602 58 : appendStringInfoString(&buffer, "text search configuration");
4603 58 : break;
4604 :
4605 54 : case AuthIdRelationId:
4606 54 : appendStringInfoString(&buffer, "role");
4607 54 : break;
4608 :
4609 12 : case AuthMemRelationId:
4610 12 : appendStringInfoString(&buffer, "role membership");
4611 12 : break;
4612 :
4613 12 : case DatabaseRelationId:
4614 12 : appendStringInfoString(&buffer, "database");
4615 12 : break;
4616 :
4617 12 : case TableSpaceRelationId:
4618 12 : appendStringInfoString(&buffer, "tablespace");
4619 12 : break;
4620 :
4621 60 : case ForeignDataWrapperRelationId:
4622 60 : appendStringInfoString(&buffer, "foreign-data wrapper");
4623 60 : break;
4624 :
4625 60 : case ForeignServerRelationId:
4626 60 : appendStringInfoString(&buffer, "server");
4627 60 : break;
4628 :
4629 60 : case UserMappingRelationId:
4630 60 : appendStringInfoString(&buffer, "user mapping");
4631 60 : break;
4632 :
4633 102 : case DefaultAclRelationId:
4634 102 : appendStringInfoString(&buffer, "default acl");
4635 102 : break;
4636 :
4637 32 : case ExtensionRelationId:
4638 32 : appendStringInfoString(&buffer, "extension");
4639 32 : break;
4640 :
4641 48 : case EventTriggerRelationId:
4642 48 : appendStringInfoString(&buffer, "event trigger");
4643 48 : break;
4644 :
4645 16 : case ParameterAclRelationId:
4646 16 : appendStringInfoString(&buffer, "parameter ACL");
4647 16 : break;
4648 :
4649 72 : case PolicyRelationId:
4650 72 : appendStringInfoString(&buffer, "policy");
4651 72 : break;
4652 :
4653 54 : case PublicationRelationId:
4654 54 : appendStringInfoString(&buffer, "publication");
4655 54 : break;
4656 :
4657 54 : case PublicationNamespaceRelationId:
4658 54 : appendStringInfoString(&buffer, "publication namespace");
4659 54 : break;
4660 :
4661 54 : case PublicationRelRelationId:
4662 54 : appendStringInfoString(&buffer, "publication relation");
4663 54 : break;
4664 :
4665 54 : case SubscriptionRelationId:
4666 54 : appendStringInfoString(&buffer, "subscription");
4667 54 : break;
4668 :
4669 58 : case TransformRelationId:
4670 58 : appendStringInfoString(&buffer, "transform");
4671 58 : break;
4672 :
4673 0 : default:
4674 0 : elog(ERROR, "unsupported object class: %u", object->classId);
4675 : }
4676 :
4677 : /* the result can never be empty */
4678 : Assert(buffer.len > 0);
4679 :
4680 6858 : return buffer.data;
4681 : }
4682 :
4683 : /*
4684 : * subroutine for getObjectTypeDescription: describe a relation type
4685 : */
4686 : static void
4687 2098 : getRelationTypeDescription(StringInfo buffer, Oid relid, int32 objectSubId,
4688 : bool missing_ok)
4689 : {
4690 : HeapTuple relTup;
4691 : Form_pg_class relForm;
4692 :
4693 2098 : relTup = SearchSysCache1(RELOID,
4694 : ObjectIdGetDatum(relid));
4695 2098 : if (!HeapTupleIsValid(relTup))
4696 : {
4697 12 : if (!missing_ok)
4698 0 : elog(ERROR, "cache lookup failed for relation %u", relid);
4699 :
4700 : /* fallback to "relation" for an undefined object */
4701 12 : appendStringInfoString(buffer, "relation");
4702 12 : return;
4703 : }
4704 2086 : relForm = (Form_pg_class) GETSTRUCT(relTup);
4705 :
4706 2086 : switch (relForm->relkind)
4707 : {
4708 904 : case RELKIND_RELATION:
4709 : case RELKIND_PARTITIONED_TABLE:
4710 904 : appendStringInfoString(buffer, "table");
4711 904 : break;
4712 660 : case RELKIND_INDEX:
4713 : case RELKIND_PARTITIONED_INDEX:
4714 660 : appendStringInfoString(buffer, "index");
4715 660 : break;
4716 188 : case RELKIND_SEQUENCE:
4717 188 : appendStringInfoString(buffer, "sequence");
4718 188 : break;
4719 102 : case RELKIND_TOASTVALUE:
4720 102 : appendStringInfoString(buffer, "toast table");
4721 102 : break;
4722 80 : case RELKIND_VIEW:
4723 80 : appendStringInfoString(buffer, "view");
4724 80 : break;
4725 60 : case RELKIND_MATVIEW:
4726 60 : appendStringInfoString(buffer, "materialized view");
4727 60 : break;
4728 2 : case RELKIND_COMPOSITE_TYPE:
4729 2 : appendStringInfoString(buffer, "composite type");
4730 2 : break;
4731 90 : case RELKIND_FOREIGN_TABLE:
4732 90 : appendStringInfoString(buffer, "foreign table");
4733 90 : break;
4734 0 : default:
4735 : /* shouldn't get here */
4736 0 : appendStringInfoString(buffer, "relation");
4737 0 : break;
4738 : }
4739 :
4740 2086 : if (objectSubId != 0)
4741 122 : appendStringInfoString(buffer, " column");
4742 :
4743 2086 : ReleaseSysCache(relTup);
4744 : }
4745 :
4746 : /*
4747 : * subroutine for getObjectTypeDescription: describe a constraint type
4748 : */
4749 : static void
4750 564 : getConstraintTypeDescription(StringInfo buffer, Oid constroid, bool missing_ok)
4751 : {
4752 : Relation constrRel;
4753 : HeapTuple constrTup;
4754 : Form_pg_constraint constrForm;
4755 :
4756 564 : constrRel = table_open(ConstraintRelationId, AccessShareLock);
4757 564 : constrTup = get_catalog_object_by_oid(constrRel, Anum_pg_constraint_oid,
4758 : constroid);
4759 564 : if (!HeapTupleIsValid(constrTup))
4760 : {
4761 12 : if (!missing_ok)
4762 0 : elog(ERROR, "cache lookup failed for constraint %u", constroid);
4763 :
4764 12 : table_close(constrRel, AccessShareLock);
4765 :
4766 : /* fallback to "constraint" for an undefined object */
4767 12 : appendStringInfoString(buffer, "constraint");
4768 12 : return;
4769 : }
4770 :
4771 552 : constrForm = (Form_pg_constraint) GETSTRUCT(constrTup);
4772 :
4773 552 : if (OidIsValid(constrForm->conrelid))
4774 510 : appendStringInfoString(buffer, "table constraint");
4775 42 : else if (OidIsValid(constrForm->contypid))
4776 42 : appendStringInfoString(buffer, "domain constraint");
4777 : else
4778 0 : elog(ERROR, "invalid constraint %u", constrForm->oid);
4779 :
4780 552 : table_close(constrRel, AccessShareLock);
4781 : }
4782 :
4783 : /*
4784 : * subroutine for getObjectTypeDescription: describe a procedure type
4785 : */
4786 : static void
4787 292 : getProcedureTypeDescription(StringInfo buffer, Oid procid,
4788 : bool missing_ok)
4789 : {
4790 : HeapTuple procTup;
4791 : Form_pg_proc procForm;
4792 :
4793 292 : procTup = SearchSysCache1(PROCOID,
4794 : ObjectIdGetDatum(procid));
4795 292 : if (!HeapTupleIsValid(procTup))
4796 : {
4797 12 : if (!missing_ok)
4798 0 : elog(ERROR, "cache lookup failed for procedure %u", procid);
4799 :
4800 : /* fallback to "procedure" for an undefined object */
4801 12 : appendStringInfoString(buffer, "routine");
4802 12 : return;
4803 : }
4804 280 : procForm = (Form_pg_proc) GETSTRUCT(procTup);
4805 :
4806 280 : if (procForm->prokind == PROKIND_AGGREGATE)
4807 60 : appendStringInfoString(buffer, "aggregate");
4808 220 : else if (procForm->prokind == PROKIND_PROCEDURE)
4809 48 : appendStringInfoString(buffer, "procedure");
4810 : else /* function or window function */
4811 172 : appendStringInfoString(buffer, "function");
4812 :
4813 280 : ReleaseSysCache(procTup);
4814 : }
4815 :
4816 : /*
4817 : * Obtain a given object's identity, as a palloc'ed string.
4818 : *
4819 : * This is for machine consumption, so it's not translated. All elements are
4820 : * schema-qualified when appropriate. Returns NULL if the object could not
4821 : * be found.
4822 : */
4823 : char *
4824 2676 : getObjectIdentity(const ObjectAddress *object, bool missing_ok)
4825 : {
4826 2676 : return getObjectIdentityParts(object, NULL, NULL, missing_ok);
4827 : }
4828 :
4829 : /*
4830 : * As above, but more detailed.
4831 : *
4832 : * There are two sets of return values: the identity itself as a palloc'd
4833 : * string is returned. objname and objargs, if not NULL, are output parameters
4834 : * that receive lists of C-strings that are useful to give back to
4835 : * get_object_address() to reconstruct the ObjectAddress. Returns NULL if
4836 : * the object could not be found.
4837 : */
4838 : char *
4839 7334 : getObjectIdentityParts(const ObjectAddress *object,
4840 : List **objname, List **objargs,
4841 : bool missing_ok)
4842 : {
4843 : StringInfoData buffer;
4844 :
4845 7334 : initStringInfo(&buffer);
4846 :
4847 : /*
4848 : * Make sure that both objname and objargs were passed, or none was; and
4849 : * initialize them to empty lists. For objname this is useless because it
4850 : * will be initialized in all cases inside the switch; but we do it anyway
4851 : * so that we can test below that no branch leaves it unset.
4852 : */
4853 : Assert(PointerIsValid(objname) == PointerIsValid(objargs));
4854 7334 : if (objname)
4855 : {
4856 4586 : *objname = NIL;
4857 4586 : *objargs = NIL;
4858 : }
4859 :
4860 7334 : switch (object->classId)
4861 : {
4862 2532 : case RelationRelationId:
4863 : {
4864 2532 : char *attr = NULL;
4865 :
4866 : /*
4867 : * Check for the attribute first, so as if it is missing we
4868 : * can skip the entire relation description.
4869 : */
4870 2532 : if (object->objectSubId != 0)
4871 : {
4872 550 : attr = get_attname(object->objectId,
4873 550 : object->objectSubId,
4874 : missing_ok);
4875 :
4876 550 : if (missing_ok && attr == NULL)
4877 12 : break;
4878 : }
4879 :
4880 2520 : getRelationIdentity(&buffer, object->objectId, objname,
4881 : missing_ok);
4882 2520 : if (objname && *objname == NIL)
4883 6 : break;
4884 :
4885 2514 : if (attr)
4886 : {
4887 538 : appendStringInfo(&buffer, ".%s",
4888 : quote_identifier(attr));
4889 538 : if (objname)
4890 428 : *objname = lappend(*objname, attr);
4891 : }
4892 : }
4893 2514 : break;
4894 :
4895 292 : case ProcedureRelationId:
4896 : {
4897 292 : bits16 flags = FORMAT_PROC_FORCE_QUALIFY | FORMAT_PROC_INVALID_AS_NULL;
4898 292 : char *proname = format_procedure_extended(object->objectId,
4899 : flags);
4900 :
4901 292 : if (proname == NULL)
4902 12 : break;
4903 :
4904 280 : appendStringInfoString(&buffer, proname);
4905 280 : if (objname)
4906 126 : format_procedure_parts(object->objectId, objname, objargs,
4907 : missing_ok);
4908 280 : break;
4909 : }
4910 :
4911 1454 : case TypeRelationId:
4912 : {
4913 1454 : bits16 flags = FORMAT_TYPE_INVALID_AS_NULL | FORMAT_TYPE_FORCE_QUALIFY;
4914 : char *typeout;
4915 :
4916 1454 : typeout = format_type_extended(object->objectId, -1, flags);
4917 :
4918 1454 : if (typeout == NULL)
4919 12 : break;
4920 :
4921 1442 : appendStringInfoString(&buffer, typeout);
4922 1442 : if (objname)
4923 1226 : *objname = list_make1(typeout);
4924 : }
4925 1442 : break;
4926 :
4927 62 : case CastRelationId:
4928 : {
4929 : Relation castRel;
4930 : HeapTuple tup;
4931 : Form_pg_cast castForm;
4932 :
4933 62 : castRel = table_open(CastRelationId, AccessShareLock);
4934 :
4935 62 : tup = get_catalog_object_by_oid(castRel, Anum_pg_cast_oid,
4936 : object->objectId);
4937 :
4938 62 : if (!HeapTupleIsValid(tup))
4939 : {
4940 12 : if (!missing_ok)
4941 0 : elog(ERROR, "could not find tuple for cast %u",
4942 : object->objectId);
4943 :
4944 12 : table_close(castRel, AccessShareLock);
4945 12 : break;
4946 : }
4947 :
4948 50 : castForm = (Form_pg_cast) GETSTRUCT(tup);
4949 :
4950 50 : appendStringInfo(&buffer, "(%s AS %s)",
4951 : format_type_be_qualified(castForm->castsource),
4952 : format_type_be_qualified(castForm->casttarget));
4953 :
4954 50 : if (objname)
4955 : {
4956 6 : *objname = list_make1(format_type_be_qualified(castForm->castsource));
4957 6 : *objargs = list_make1(format_type_be_qualified(castForm->casttarget));
4958 : }
4959 :
4960 50 : table_close(castRel, AccessShareLock);
4961 50 : break;
4962 : }
4963 :
4964 54 : case CollationRelationId:
4965 : {
4966 : HeapTuple collTup;
4967 : Form_pg_collation coll;
4968 : char *schema;
4969 :
4970 54 : collTup = SearchSysCache1(COLLOID,
4971 : ObjectIdGetDatum(object->objectId));
4972 54 : if (!HeapTupleIsValid(collTup))
4973 : {
4974 12 : if (!missing_ok)
4975 0 : elog(ERROR, "cache lookup failed for collation %u",
4976 : object->objectId);
4977 12 : break;
4978 : }
4979 42 : coll = (Form_pg_collation) GETSTRUCT(collTup);
4980 42 : schema = get_namespace_name_or_temp(coll->collnamespace);
4981 42 : appendStringInfoString(&buffer,
4982 42 : quote_qualified_identifier(schema,
4983 42 : NameStr(coll->collname)));
4984 42 : if (objname)
4985 6 : *objname = list_make2(schema,
4986 : pstrdup(NameStr(coll->collname)));
4987 42 : ReleaseSysCache(collTup);
4988 42 : break;
4989 : }
4990 :
4991 564 : case ConstraintRelationId:
4992 : {
4993 : HeapTuple conTup;
4994 : Form_pg_constraint con;
4995 :
4996 564 : conTup = SearchSysCache1(CONSTROID,
4997 : ObjectIdGetDatum(object->objectId));
4998 564 : if (!HeapTupleIsValid(conTup))
4999 : {
5000 12 : if (!missing_ok)
5001 0 : elog(ERROR, "cache lookup failed for constraint %u",
5002 : object->objectId);
5003 12 : break;
5004 : }
5005 552 : con = (Form_pg_constraint) GETSTRUCT(conTup);
5006 :
5007 552 : if (OidIsValid(con->conrelid))
5008 : {
5009 510 : appendStringInfo(&buffer, "%s on ",
5010 510 : quote_identifier(NameStr(con->conname)));
5011 510 : getRelationIdentity(&buffer, con->conrelid, objname,
5012 : false);
5013 510 : if (objname)
5014 474 : *objname = lappend(*objname, pstrdup(NameStr(con->conname)));
5015 : }
5016 : else
5017 : {
5018 : ObjectAddress domain;
5019 :
5020 : Assert(OidIsValid(con->contypid));
5021 42 : domain.classId = TypeRelationId;
5022 42 : domain.objectId = con->contypid;
5023 42 : domain.objectSubId = 0;
5024 :
5025 84 : appendStringInfo(&buffer, "%s on %s",
5026 42 : quote_identifier(NameStr(con->conname)),
5027 : getObjectIdentityParts(&domain, objname,
5028 : objargs, false));
5029 :
5030 42 : if (objname)
5031 6 : *objargs = lappend(*objargs, pstrdup(NameStr(con->conname)));
5032 : }
5033 :
5034 552 : ReleaseSysCache(conTup);
5035 552 : break;
5036 : }
5037 :
5038 56 : case ConversionRelationId:
5039 : {
5040 : HeapTuple conTup;
5041 : Form_pg_conversion conForm;
5042 : char *schema;
5043 :
5044 56 : conTup = SearchSysCache1(CONVOID,
5045 : ObjectIdGetDatum(object->objectId));
5046 56 : if (!HeapTupleIsValid(conTup))
5047 : {
5048 12 : if (!missing_ok)
5049 0 : elog(ERROR, "cache lookup failed for conversion %u",
5050 : object->objectId);
5051 12 : break;
5052 : }
5053 44 : conForm = (Form_pg_conversion) GETSTRUCT(conTup);
5054 44 : schema = get_namespace_name_or_temp(conForm->connamespace);
5055 44 : appendStringInfoString(&buffer,
5056 44 : quote_qualified_identifier(schema,
5057 44 : NameStr(conForm->conname)));
5058 44 : if (objname)
5059 6 : *objname = list_make2(schema,
5060 : pstrdup(NameStr(conForm->conname)));
5061 44 : ReleaseSysCache(conTup);
5062 44 : break;
5063 : }
5064 :
5065 440 : case AttrDefaultRelationId:
5066 : {
5067 : ObjectAddress colobject;
5068 :
5069 440 : colobject = GetAttrDefaultColumnAddress(object->objectId);
5070 :
5071 440 : if (!OidIsValid(colobject.objectId))
5072 : {
5073 12 : if (!missing_ok)
5074 0 : elog(ERROR, "could not find tuple for attrdef %u",
5075 : object->objectId);
5076 12 : break;
5077 : }
5078 :
5079 428 : appendStringInfo(&buffer, "for %s",
5080 : getObjectIdentityParts(&colobject,
5081 : objname, objargs,
5082 : false));
5083 428 : break;
5084 : }
5085 :
5086 54 : case LanguageRelationId:
5087 : {
5088 : HeapTuple langTup;
5089 : Form_pg_language langForm;
5090 :
5091 54 : langTup = SearchSysCache1(LANGOID,
5092 : ObjectIdGetDatum(object->objectId));
5093 54 : if (!HeapTupleIsValid(langTup))
5094 : {
5095 12 : if (!missing_ok)
5096 0 : elog(ERROR, "cache lookup failed for language %u",
5097 : object->objectId);
5098 12 : break;
5099 : }
5100 42 : langForm = (Form_pg_language) GETSTRUCT(langTup);
5101 42 : appendStringInfoString(&buffer,
5102 42 : quote_identifier(NameStr(langForm->lanname)));
5103 42 : if (objname)
5104 6 : *objname = list_make1(pstrdup(NameStr(langForm->lanname)));
5105 42 : ReleaseSysCache(langTup);
5106 42 : break;
5107 : }
5108 :
5109 12 : case LargeObjectRelationId:
5110 12 : if (!LargeObjectExists(object->objectId))
5111 12 : break;
5112 0 : appendStringInfo(&buffer, "%u",
5113 : object->objectId);
5114 0 : if (objname)
5115 0 : *objname = list_make1(psprintf("%u", object->objectId));
5116 0 : break;
5117 :
5118 58 : case OperatorRelationId:
5119 : {
5120 58 : bits16 flags = FORMAT_OPERATOR_FORCE_QUALIFY | FORMAT_OPERATOR_INVALID_AS_NULL;
5121 58 : char *oprname = format_operator_extended(object->objectId,
5122 : flags);
5123 :
5124 58 : if (oprname == NULL)
5125 12 : break;
5126 :
5127 46 : appendStringInfoString(&buffer, oprname);
5128 46 : if (objname)
5129 6 : format_operator_parts(object->objectId, objname, objargs, missing_ok);
5130 46 : break;
5131 : }
5132 :
5133 62 : case OperatorClassRelationId:
5134 : {
5135 : HeapTuple opcTup;
5136 : Form_pg_opclass opcForm;
5137 : HeapTuple amTup;
5138 : Form_pg_am amForm;
5139 : char *schema;
5140 :
5141 62 : opcTup = SearchSysCache1(CLAOID,
5142 : ObjectIdGetDatum(object->objectId));
5143 62 : if (!HeapTupleIsValid(opcTup))
5144 : {
5145 12 : if (!missing_ok)
5146 0 : elog(ERROR, "cache lookup failed for opclass %u",
5147 : object->objectId);
5148 12 : break;
5149 : }
5150 50 : opcForm = (Form_pg_opclass) GETSTRUCT(opcTup);
5151 50 : schema = get_namespace_name_or_temp(opcForm->opcnamespace);
5152 :
5153 50 : amTup = SearchSysCache1(AMOID,
5154 : ObjectIdGetDatum(opcForm->opcmethod));
5155 50 : if (!HeapTupleIsValid(amTup))
5156 0 : elog(ERROR, "cache lookup failed for access method %u",
5157 : opcForm->opcmethod);
5158 50 : amForm = (Form_pg_am) GETSTRUCT(amTup);
5159 :
5160 50 : appendStringInfo(&buffer, "%s USING %s",
5161 : quote_qualified_identifier(schema,
5162 50 : NameStr(opcForm->opcname)),
5163 50 : quote_identifier(NameStr(amForm->amname)));
5164 50 : if (objname)
5165 6 : *objname = list_make3(pstrdup(NameStr(amForm->amname)),
5166 : schema,
5167 : pstrdup(NameStr(opcForm->opcname)));
5168 :
5169 50 : ReleaseSysCache(amTup);
5170 50 : ReleaseSysCache(opcTup);
5171 50 : break;
5172 : }
5173 :
5174 64 : case OperatorFamilyRelationId:
5175 64 : getOpFamilyIdentity(&buffer, object->objectId, objname,
5176 : missing_ok);
5177 64 : break;
5178 :
5179 54 : case AccessMethodRelationId:
5180 : {
5181 : char *amname;
5182 :
5183 54 : amname = get_am_name(object->objectId);
5184 54 : if (!amname)
5185 : {
5186 12 : if (!missing_ok)
5187 0 : elog(ERROR, "cache lookup failed for access method %u",
5188 : object->objectId);
5189 12 : break;
5190 : }
5191 42 : appendStringInfoString(&buffer, quote_identifier(amname));
5192 42 : if (objname)
5193 6 : *objname = list_make1(amname);
5194 : }
5195 42 : break;
5196 :
5197 54 : case AccessMethodOperatorRelationId:
5198 : {
5199 : Relation amopDesc;
5200 : HeapTuple tup;
5201 : ScanKeyData skey[1];
5202 : SysScanDesc amscan;
5203 : Form_pg_amop amopForm;
5204 : StringInfoData opfam;
5205 : char *ltype;
5206 : char *rtype;
5207 :
5208 54 : amopDesc = table_open(AccessMethodOperatorRelationId,
5209 : AccessShareLock);
5210 :
5211 54 : ScanKeyInit(&skey[0],
5212 : Anum_pg_amop_oid,
5213 : BTEqualStrategyNumber, F_OIDEQ,
5214 : ObjectIdGetDatum(object->objectId));
5215 :
5216 54 : amscan = systable_beginscan(amopDesc, AccessMethodOperatorOidIndexId, true,
5217 : NULL, 1, skey);
5218 :
5219 54 : tup = systable_getnext(amscan);
5220 :
5221 54 : if (!HeapTupleIsValid(tup))
5222 : {
5223 12 : if (!missing_ok)
5224 0 : elog(ERROR, "could not find tuple for amop entry %u",
5225 : object->objectId);
5226 :
5227 12 : systable_endscan(amscan);
5228 12 : table_close(amopDesc, AccessShareLock);
5229 12 : break;
5230 : }
5231 :
5232 42 : amopForm = (Form_pg_amop) GETSTRUCT(tup);
5233 :
5234 42 : initStringInfo(&opfam);
5235 42 : getOpFamilyIdentity(&opfam, amopForm->amopfamily, objname,
5236 : false);
5237 :
5238 42 : ltype = format_type_be_qualified(amopForm->amoplefttype);
5239 42 : rtype = format_type_be_qualified(amopForm->amoprighttype);
5240 :
5241 42 : if (objname)
5242 : {
5243 6 : *objname = lappend(*objname,
5244 6 : psprintf("%d", amopForm->amopstrategy));
5245 6 : *objargs = list_make2(ltype, rtype);
5246 : }
5247 :
5248 42 : appendStringInfo(&buffer, "operator %d (%s, %s) of %s",
5249 42 : amopForm->amopstrategy,
5250 : ltype, rtype, opfam.data);
5251 :
5252 42 : pfree(opfam.data);
5253 :
5254 42 : systable_endscan(amscan);
5255 42 : table_close(amopDesc, AccessShareLock);
5256 42 : break;
5257 : }
5258 :
5259 54 : case AccessMethodProcedureRelationId:
5260 : {
5261 : Relation amprocDesc;
5262 : ScanKeyData skey[1];
5263 : SysScanDesc amscan;
5264 : HeapTuple tup;
5265 : Form_pg_amproc amprocForm;
5266 : StringInfoData opfam;
5267 : char *ltype;
5268 : char *rtype;
5269 :
5270 54 : amprocDesc = table_open(AccessMethodProcedureRelationId,
5271 : AccessShareLock);
5272 :
5273 54 : ScanKeyInit(&skey[0],
5274 : Anum_pg_amproc_oid,
5275 : BTEqualStrategyNumber, F_OIDEQ,
5276 : ObjectIdGetDatum(object->objectId));
5277 :
5278 54 : amscan = systable_beginscan(amprocDesc, AccessMethodProcedureOidIndexId, true,
5279 : NULL, 1, skey);
5280 :
5281 54 : tup = systable_getnext(amscan);
5282 :
5283 54 : if (!HeapTupleIsValid(tup))
5284 : {
5285 12 : if (!missing_ok)
5286 0 : elog(ERROR, "could not find tuple for amproc entry %u",
5287 : object->objectId);
5288 :
5289 12 : systable_endscan(amscan);
5290 12 : table_close(amprocDesc, AccessShareLock);
5291 12 : break;
5292 : }
5293 :
5294 42 : amprocForm = (Form_pg_amproc) GETSTRUCT(tup);
5295 :
5296 42 : initStringInfo(&opfam);
5297 42 : getOpFamilyIdentity(&opfam, amprocForm->amprocfamily, objname,
5298 : false);
5299 :
5300 42 : ltype = format_type_be_qualified(amprocForm->amproclefttype);
5301 42 : rtype = format_type_be_qualified(amprocForm->amprocrighttype);
5302 :
5303 42 : if (objname)
5304 : {
5305 6 : *objname = lappend(*objname,
5306 6 : psprintf("%d", amprocForm->amprocnum));
5307 6 : *objargs = list_make2(ltype, rtype);
5308 : }
5309 :
5310 42 : appendStringInfo(&buffer, "function %d (%s, %s) of %s",
5311 42 : amprocForm->amprocnum,
5312 : ltype, rtype, opfam.data);
5313 :
5314 42 : pfree(opfam.data);
5315 :
5316 42 : systable_endscan(amscan);
5317 42 : table_close(amprocDesc, AccessShareLock);
5318 42 : break;
5319 : }
5320 :
5321 86 : case RewriteRelationId:
5322 : {
5323 : Relation ruleDesc;
5324 : HeapTuple tup;
5325 : Form_pg_rewrite rule;
5326 :
5327 86 : ruleDesc = table_open(RewriteRelationId, AccessShareLock);
5328 :
5329 86 : tup = get_catalog_object_by_oid(ruleDesc, Anum_pg_rewrite_oid,
5330 : object->objectId);
5331 :
5332 86 : if (!HeapTupleIsValid(tup))
5333 : {
5334 12 : if (!missing_ok)
5335 0 : elog(ERROR, "could not find tuple for rule %u",
5336 : object->objectId);
5337 :
5338 12 : table_close(ruleDesc, AccessShareLock);
5339 12 : break;
5340 : }
5341 :
5342 74 : rule = (Form_pg_rewrite) GETSTRUCT(tup);
5343 :
5344 74 : appendStringInfo(&buffer, "%s on ",
5345 74 : quote_identifier(NameStr(rule->rulename)));
5346 74 : getRelationIdentity(&buffer, rule->ev_class, objname, false);
5347 74 : if (objname)
5348 28 : *objname = lappend(*objname, pstrdup(NameStr(rule->rulename)));
5349 :
5350 74 : table_close(ruleDesc, AccessShareLock);
5351 74 : break;
5352 : }
5353 :
5354 156 : case TriggerRelationId:
5355 : {
5356 : Relation trigDesc;
5357 : HeapTuple tup;
5358 : Form_pg_trigger trig;
5359 :
5360 156 : trigDesc = table_open(TriggerRelationId, AccessShareLock);
5361 :
5362 156 : tup = get_catalog_object_by_oid(trigDesc, Anum_pg_trigger_oid,
5363 : object->objectId);
5364 :
5365 156 : if (!HeapTupleIsValid(tup))
5366 : {
5367 12 : if (!missing_ok)
5368 0 : elog(ERROR, "could not find tuple for trigger %u",
5369 : object->objectId);
5370 :
5371 12 : table_close(trigDesc, AccessShareLock);
5372 12 : break;
5373 : }
5374 :
5375 144 : trig = (Form_pg_trigger) GETSTRUCT(tup);
5376 :
5377 144 : appendStringInfo(&buffer, "%s on ",
5378 144 : quote_identifier(NameStr(trig->tgname)));
5379 144 : getRelationIdentity(&buffer, trig->tgrelid, objname, false);
5380 144 : if (objname)
5381 102 : *objname = lappend(*objname, pstrdup(NameStr(trig->tgname)));
5382 :
5383 144 : table_close(trigDesc, AccessShareLock);
5384 144 : break;
5385 : }
5386 :
5387 136 : case NamespaceRelationId:
5388 : {
5389 : char *nspname;
5390 :
5391 136 : nspname = get_namespace_name_or_temp(object->objectId);
5392 136 : if (!nspname)
5393 : {
5394 12 : if (!missing_ok)
5395 0 : elog(ERROR, "cache lookup failed for namespace %u",
5396 : object->objectId);
5397 12 : break;
5398 : }
5399 124 : appendStringInfoString(&buffer,
5400 : quote_identifier(nspname));
5401 124 : if (objname)
5402 72 : *objname = list_make1(nspname);
5403 124 : break;
5404 : }
5405 :
5406 56 : case StatisticExtRelationId:
5407 : {
5408 : HeapTuple tup;
5409 : Form_pg_statistic_ext formStatistic;
5410 : char *schema;
5411 :
5412 56 : tup = SearchSysCache1(STATEXTOID,
5413 : ObjectIdGetDatum(object->objectId));
5414 56 : if (!HeapTupleIsValid(tup))
5415 : {
5416 12 : if (!missing_ok)
5417 0 : elog(ERROR, "cache lookup failed for statistics object %u",
5418 : object->objectId);
5419 12 : break;
5420 : }
5421 44 : formStatistic = (Form_pg_statistic_ext) GETSTRUCT(tup);
5422 44 : schema = get_namespace_name_or_temp(formStatistic->stxnamespace);
5423 44 : appendStringInfoString(&buffer,
5424 44 : quote_qualified_identifier(schema,
5425 44 : NameStr(formStatistic->stxname)));
5426 44 : if (objname)
5427 6 : *objname = list_make2(schema,
5428 : pstrdup(NameStr(formStatistic->stxname)));
5429 44 : ReleaseSysCache(tup);
5430 : }
5431 44 : break;
5432 :
5433 54 : case TSParserRelationId:
5434 : {
5435 : HeapTuple tup;
5436 : Form_pg_ts_parser formParser;
5437 : char *schema;
5438 :
5439 54 : tup = SearchSysCache1(TSPARSEROID,
5440 : ObjectIdGetDatum(object->objectId));
5441 54 : if (!HeapTupleIsValid(tup))
5442 : {
5443 12 : if (!missing_ok)
5444 0 : elog(ERROR, "cache lookup failed for text search parser %u",
5445 : object->objectId);
5446 12 : break;
5447 : }
5448 42 : formParser = (Form_pg_ts_parser) GETSTRUCT(tup);
5449 42 : schema = get_namespace_name_or_temp(formParser->prsnamespace);
5450 42 : appendStringInfoString(&buffer,
5451 42 : quote_qualified_identifier(schema,
5452 42 : NameStr(formParser->prsname)));
5453 42 : if (objname)
5454 6 : *objname = list_make2(schema,
5455 : pstrdup(NameStr(formParser->prsname)));
5456 42 : ReleaseSysCache(tup);
5457 42 : break;
5458 : }
5459 :
5460 54 : case TSDictionaryRelationId:
5461 : {
5462 : HeapTuple tup;
5463 : Form_pg_ts_dict formDict;
5464 : char *schema;
5465 :
5466 54 : tup = SearchSysCache1(TSDICTOID,
5467 : ObjectIdGetDatum(object->objectId));
5468 54 : if (!HeapTupleIsValid(tup))
5469 : {
5470 12 : if (!missing_ok)
5471 0 : elog(ERROR, "cache lookup failed for text search dictionary %u",
5472 : object->objectId);
5473 12 : break;
5474 : }
5475 42 : formDict = (Form_pg_ts_dict) GETSTRUCT(tup);
5476 42 : schema = get_namespace_name_or_temp(formDict->dictnamespace);
5477 42 : appendStringInfoString(&buffer,
5478 42 : quote_qualified_identifier(schema,
5479 42 : NameStr(formDict->dictname)));
5480 42 : if (objname)
5481 6 : *objname = list_make2(schema,
5482 : pstrdup(NameStr(formDict->dictname)));
5483 42 : ReleaseSysCache(tup);
5484 42 : break;
5485 : }
5486 :
5487 54 : case TSTemplateRelationId:
5488 : {
5489 : HeapTuple tup;
5490 : Form_pg_ts_template formTmpl;
5491 : char *schema;
5492 :
5493 54 : tup = SearchSysCache1(TSTEMPLATEOID,
5494 : ObjectIdGetDatum(object->objectId));
5495 54 : if (!HeapTupleIsValid(tup))
5496 : {
5497 12 : if (!missing_ok)
5498 0 : elog(ERROR, "cache lookup failed for text search template %u",
5499 : object->objectId);
5500 12 : break;
5501 : }
5502 42 : formTmpl = (Form_pg_ts_template) GETSTRUCT(tup);
5503 42 : schema = get_namespace_name_or_temp(formTmpl->tmplnamespace);
5504 42 : appendStringInfoString(&buffer,
5505 42 : quote_qualified_identifier(schema,
5506 42 : NameStr(formTmpl->tmplname)));
5507 42 : if (objname)
5508 6 : *objname = list_make2(schema,
5509 : pstrdup(NameStr(formTmpl->tmplname)));
5510 42 : ReleaseSysCache(tup);
5511 42 : break;
5512 : }
5513 :
5514 58 : case TSConfigRelationId:
5515 : {
5516 : HeapTuple tup;
5517 : Form_pg_ts_config formCfg;
5518 : char *schema;
5519 :
5520 58 : tup = SearchSysCache1(TSCONFIGOID,
5521 : ObjectIdGetDatum(object->objectId));
5522 58 : if (!HeapTupleIsValid(tup))
5523 : {
5524 12 : if (!missing_ok)
5525 0 : elog(ERROR, "cache lookup failed for text search configuration %u",
5526 : object->objectId);
5527 12 : break;
5528 : }
5529 46 : formCfg = (Form_pg_ts_config) GETSTRUCT(tup);
5530 46 : schema = get_namespace_name_or_temp(formCfg->cfgnamespace);
5531 46 : appendStringInfoString(&buffer,
5532 46 : quote_qualified_identifier(schema,
5533 46 : NameStr(formCfg->cfgname)));
5534 46 : if (objname)
5535 6 : *objname = list_make2(schema,
5536 : pstrdup(NameStr(formCfg->cfgname)));
5537 46 : ReleaseSysCache(tup);
5538 46 : break;
5539 : }
5540 :
5541 54 : case AuthIdRelationId:
5542 : {
5543 : char *username;
5544 :
5545 54 : username = GetUserNameFromId(object->objectId, missing_ok);
5546 54 : if (!username)
5547 12 : break;
5548 42 : if (objname)
5549 6 : *objname = list_make1(username);
5550 42 : appendStringInfoString(&buffer,
5551 : quote_identifier(username));
5552 42 : break;
5553 : }
5554 :
5555 12 : case AuthMemRelationId:
5556 : {
5557 : Relation authMemDesc;
5558 : ScanKeyData skey[1];
5559 : SysScanDesc amscan;
5560 : HeapTuple tup;
5561 : Form_pg_auth_members amForm;
5562 :
5563 12 : authMemDesc = table_open(AuthMemRelationId,
5564 : AccessShareLock);
5565 :
5566 12 : ScanKeyInit(&skey[0],
5567 : Anum_pg_auth_members_oid,
5568 : BTEqualStrategyNumber, F_OIDEQ,
5569 : ObjectIdGetDatum(object->objectId));
5570 :
5571 12 : amscan = systable_beginscan(authMemDesc, AuthMemOidIndexId, true,
5572 : NULL, 1, skey);
5573 :
5574 12 : tup = systable_getnext(amscan);
5575 :
5576 12 : if (!HeapTupleIsValid(tup))
5577 : {
5578 12 : if (!missing_ok)
5579 0 : elog(ERROR, "could not find tuple for pg_auth_members entry %u",
5580 : object->objectId);
5581 :
5582 12 : systable_endscan(amscan);
5583 12 : table_close(authMemDesc, AccessShareLock);
5584 12 : break;
5585 : }
5586 :
5587 0 : amForm = (Form_pg_auth_members) GETSTRUCT(tup);
5588 :
5589 0 : appendStringInfo(&buffer, _("membership of role %s in role %s"),
5590 : GetUserNameFromId(amForm->member, false),
5591 : GetUserNameFromId(amForm->roleid, false));
5592 :
5593 0 : systable_endscan(amscan);
5594 0 : table_close(authMemDesc, AccessShareLock);
5595 0 : break;
5596 : }
5597 :
5598 12 : case DatabaseRelationId:
5599 : {
5600 : char *datname;
5601 :
5602 12 : datname = get_database_name(object->objectId);
5603 12 : if (!datname)
5604 : {
5605 12 : if (!missing_ok)
5606 0 : elog(ERROR, "cache lookup failed for database %u",
5607 : object->objectId);
5608 12 : break;
5609 : }
5610 0 : if (objname)
5611 0 : *objname = list_make1(datname);
5612 0 : appendStringInfoString(&buffer,
5613 : quote_identifier(datname));
5614 0 : break;
5615 : }
5616 :
5617 12 : case TableSpaceRelationId:
5618 : {
5619 : char *tblspace;
5620 :
5621 12 : tblspace = get_tablespace_name(object->objectId);
5622 12 : if (!tblspace)
5623 : {
5624 12 : if (!missing_ok)
5625 0 : elog(ERROR, "cache lookup failed for tablespace %u",
5626 : object->objectId);
5627 12 : break;
5628 : }
5629 0 : if (objname)
5630 0 : *objname = list_make1(tblspace);
5631 0 : appendStringInfoString(&buffer,
5632 : quote_identifier(tblspace));
5633 0 : break;
5634 : }
5635 :
5636 60 : case ForeignDataWrapperRelationId:
5637 : {
5638 : ForeignDataWrapper *fdw;
5639 :
5640 60 : fdw = GetForeignDataWrapperExtended(object->objectId,
5641 : missing_ok);
5642 60 : if (fdw)
5643 : {
5644 48 : appendStringInfoString(&buffer, quote_identifier(fdw->fdwname));
5645 48 : if (objname)
5646 12 : *objname = list_make1(pstrdup(fdw->fdwname));
5647 : }
5648 60 : break;
5649 : }
5650 :
5651 60 : case ForeignServerRelationId:
5652 : {
5653 : ForeignServer *srv;
5654 :
5655 60 : srv = GetForeignServerExtended(object->objectId,
5656 : missing_ok);
5657 60 : if (srv)
5658 : {
5659 48 : appendStringInfoString(&buffer,
5660 48 : quote_identifier(srv->servername));
5661 48 : if (objname)
5662 12 : *objname = list_make1(pstrdup(srv->servername));
5663 : }
5664 60 : break;
5665 : }
5666 :
5667 60 : case UserMappingRelationId:
5668 : {
5669 : HeapTuple tup;
5670 : Oid useid;
5671 : Form_pg_user_mapping umform;
5672 : ForeignServer *srv;
5673 : const char *usename;
5674 :
5675 60 : tup = SearchSysCache1(USERMAPPINGOID,
5676 : ObjectIdGetDatum(object->objectId));
5677 60 : if (!HeapTupleIsValid(tup))
5678 : {
5679 12 : if (!missing_ok)
5680 0 : elog(ERROR, "cache lookup failed for user mapping %u",
5681 : object->objectId);
5682 12 : break;
5683 : }
5684 48 : umform = (Form_pg_user_mapping) GETSTRUCT(tup);
5685 48 : useid = umform->umuser;
5686 48 : srv = GetForeignServer(umform->umserver);
5687 :
5688 48 : ReleaseSysCache(tup);
5689 :
5690 48 : if (OidIsValid(useid))
5691 48 : usename = GetUserNameFromId(useid, false);
5692 : else
5693 0 : usename = "public";
5694 :
5695 48 : if (objname)
5696 : {
5697 12 : *objname = list_make1(pstrdup(usename));
5698 12 : *objargs = list_make1(pstrdup(srv->servername));
5699 : }
5700 :
5701 48 : appendStringInfo(&buffer, "%s on server %s",
5702 : quote_identifier(usename),
5703 : srv->servername);
5704 48 : break;
5705 : }
5706 :
5707 102 : case DefaultAclRelationId:
5708 : {
5709 : Relation defaclrel;
5710 : ScanKeyData skey[1];
5711 : SysScanDesc rcscan;
5712 : HeapTuple tup;
5713 : Form_pg_default_acl defacl;
5714 : char *schema;
5715 : char *username;
5716 :
5717 102 : defaclrel = table_open(DefaultAclRelationId, AccessShareLock);
5718 :
5719 102 : ScanKeyInit(&skey[0],
5720 : Anum_pg_default_acl_oid,
5721 : BTEqualStrategyNumber, F_OIDEQ,
5722 : ObjectIdGetDatum(object->objectId));
5723 :
5724 102 : rcscan = systable_beginscan(defaclrel, DefaultAclOidIndexId,
5725 : true, NULL, 1, skey);
5726 :
5727 102 : tup = systable_getnext(rcscan);
5728 :
5729 102 : if (!HeapTupleIsValid(tup))
5730 : {
5731 12 : if (!missing_ok)
5732 0 : elog(ERROR, "could not find tuple for default ACL %u",
5733 : object->objectId);
5734 :
5735 12 : systable_endscan(rcscan);
5736 12 : table_close(defaclrel, AccessShareLock);
5737 12 : break;
5738 : }
5739 :
5740 90 : defacl = (Form_pg_default_acl) GETSTRUCT(tup);
5741 :
5742 90 : username = GetUserNameFromId(defacl->defaclrole, false);
5743 90 : appendStringInfo(&buffer,
5744 : "for role %s",
5745 : quote_identifier(username));
5746 :
5747 90 : if (OidIsValid(defacl->defaclnamespace))
5748 : {
5749 42 : schema = get_namespace_name_or_temp(defacl->defaclnamespace);
5750 42 : appendStringInfo(&buffer,
5751 : " in schema %s",
5752 : quote_identifier(schema));
5753 : }
5754 : else
5755 48 : schema = NULL;
5756 :
5757 90 : switch (defacl->defaclobjtype)
5758 : {
5759 90 : case DEFACLOBJ_RELATION:
5760 90 : appendStringInfoString(&buffer,
5761 : " on tables");
5762 90 : break;
5763 0 : case DEFACLOBJ_SEQUENCE:
5764 0 : appendStringInfoString(&buffer,
5765 : " on sequences");
5766 0 : break;
5767 0 : case DEFACLOBJ_FUNCTION:
5768 0 : appendStringInfoString(&buffer,
5769 : " on functions");
5770 0 : break;
5771 0 : case DEFACLOBJ_TYPE:
5772 0 : appendStringInfoString(&buffer,
5773 : " on types");
5774 0 : break;
5775 0 : case DEFACLOBJ_NAMESPACE:
5776 0 : appendStringInfoString(&buffer,
5777 : " on schemas");
5778 0 : break;
5779 0 : case DEFACLOBJ_LARGEOBJECT:
5780 0 : appendStringInfoString(&buffer,
5781 : " on large objects");
5782 0 : break;
5783 : }
5784 :
5785 90 : if (objname)
5786 : {
5787 18 : *objname = list_make1(username);
5788 18 : if (schema)
5789 6 : *objname = lappend(*objname, schema);
5790 18 : *objargs = list_make1(psprintf("%c", defacl->defaclobjtype));
5791 : }
5792 :
5793 90 : systable_endscan(rcscan);
5794 90 : table_close(defaclrel, AccessShareLock);
5795 90 : break;
5796 : }
5797 :
5798 32 : case ExtensionRelationId:
5799 : {
5800 : char *extname;
5801 :
5802 32 : extname = get_extension_name(object->objectId);
5803 32 : if (!extname)
5804 : {
5805 12 : if (!missing_ok)
5806 0 : elog(ERROR, "cache lookup failed for extension %u",
5807 : object->objectId);
5808 12 : break;
5809 : }
5810 20 : appendStringInfoString(&buffer, quote_identifier(extname));
5811 20 : if (objname)
5812 0 : *objname = list_make1(extname);
5813 20 : break;
5814 : }
5815 :
5816 48 : case EventTriggerRelationId:
5817 : {
5818 : HeapTuple tup;
5819 : Form_pg_event_trigger trigForm;
5820 : char *evtname;
5821 :
5822 48 : tup = SearchSysCache1(EVENTTRIGGEROID,
5823 : ObjectIdGetDatum(object->objectId));
5824 48 : if (!HeapTupleIsValid(tup))
5825 : {
5826 12 : if (!missing_ok)
5827 0 : elog(ERROR, "cache lookup failed for event trigger %u",
5828 : object->objectId);
5829 12 : break;
5830 : }
5831 36 : trigForm = (Form_pg_event_trigger) GETSTRUCT(tup);
5832 36 : evtname = pstrdup(NameStr(trigForm->evtname));
5833 36 : appendStringInfoString(&buffer, quote_identifier(evtname));
5834 36 : if (objname)
5835 18 : *objname = list_make1(evtname);
5836 36 : ReleaseSysCache(tup);
5837 36 : break;
5838 : }
5839 :
5840 16 : case ParameterAclRelationId:
5841 : {
5842 : HeapTuple tup;
5843 : Datum nameDatum;
5844 : char *parname;
5845 :
5846 16 : tup = SearchSysCache1(PARAMETERACLOID,
5847 : ObjectIdGetDatum(object->objectId));
5848 16 : if (!HeapTupleIsValid(tup))
5849 : {
5850 12 : if (!missing_ok)
5851 0 : elog(ERROR, "cache lookup failed for parameter ACL %u",
5852 : object->objectId);
5853 12 : break;
5854 : }
5855 4 : nameDatum = SysCacheGetAttrNotNull(PARAMETERACLOID, tup,
5856 : Anum_pg_parameter_acl_parname);
5857 4 : parname = TextDatumGetCString(nameDatum);
5858 4 : appendStringInfoString(&buffer, parname);
5859 4 : if (objname)
5860 2 : *objname = list_make1(parname);
5861 4 : ReleaseSysCache(tup);
5862 4 : break;
5863 : }
5864 :
5865 72 : case PolicyRelationId:
5866 : {
5867 : Relation polDesc;
5868 : HeapTuple tup;
5869 : Form_pg_policy policy;
5870 :
5871 72 : polDesc = table_open(PolicyRelationId, AccessShareLock);
5872 :
5873 72 : tup = get_catalog_object_by_oid(polDesc, Anum_pg_policy_oid,
5874 : object->objectId);
5875 :
5876 72 : if (!HeapTupleIsValid(tup))
5877 : {
5878 12 : if (!missing_ok)
5879 0 : elog(ERROR, "could not find tuple for policy %u",
5880 : object->objectId);
5881 :
5882 12 : table_close(polDesc, AccessShareLock);
5883 12 : break;
5884 : }
5885 :
5886 60 : policy = (Form_pg_policy) GETSTRUCT(tup);
5887 :
5888 60 : appendStringInfo(&buffer, "%s on ",
5889 60 : quote_identifier(NameStr(policy->polname)));
5890 60 : getRelationIdentity(&buffer, policy->polrelid, objname, false);
5891 60 : if (objname)
5892 24 : *objname = lappend(*objname, pstrdup(NameStr(policy->polname)));
5893 :
5894 60 : table_close(polDesc, AccessShareLock);
5895 60 : break;
5896 : }
5897 :
5898 54 : case PublicationRelationId:
5899 : {
5900 : char *pubname;
5901 :
5902 54 : pubname = get_publication_name(object->objectId, missing_ok);
5903 54 : if (pubname)
5904 : {
5905 42 : appendStringInfoString(&buffer,
5906 : quote_identifier(pubname));
5907 42 : if (objname)
5908 6 : *objname = list_make1(pubname);
5909 : }
5910 54 : break;
5911 : }
5912 :
5913 54 : case PublicationNamespaceRelationId:
5914 : {
5915 : char *pubname;
5916 : char *nspname;
5917 :
5918 54 : if (!getPublicationSchemaInfo(object, missing_ok, &pubname,
5919 : &nspname))
5920 12 : break;
5921 42 : appendStringInfo(&buffer, "%s in publication %s",
5922 : nspname, pubname);
5923 :
5924 42 : if (objargs)
5925 6 : *objargs = list_make1(pubname);
5926 : else
5927 36 : pfree(pubname);
5928 :
5929 42 : if (objname)
5930 6 : *objname = list_make1(nspname);
5931 : else
5932 36 : pfree(nspname);
5933 :
5934 42 : break;
5935 : }
5936 :
5937 54 : case PublicationRelRelationId:
5938 : {
5939 : HeapTuple tup;
5940 : char *pubname;
5941 : Form_pg_publication_rel prform;
5942 :
5943 54 : tup = SearchSysCache1(PUBLICATIONREL,
5944 : ObjectIdGetDatum(object->objectId));
5945 54 : if (!HeapTupleIsValid(tup))
5946 : {
5947 12 : if (!missing_ok)
5948 0 : elog(ERROR, "cache lookup failed for publication table %u",
5949 : object->objectId);
5950 12 : break;
5951 : }
5952 :
5953 42 : prform = (Form_pg_publication_rel) GETSTRUCT(tup);
5954 42 : pubname = get_publication_name(prform->prpubid, false);
5955 :
5956 42 : getRelationIdentity(&buffer, prform->prrelid, objname, false);
5957 42 : appendStringInfo(&buffer, " in publication %s", pubname);
5958 :
5959 42 : if (objargs)
5960 6 : *objargs = list_make1(pubname);
5961 :
5962 42 : ReleaseSysCache(tup);
5963 42 : break;
5964 : }
5965 :
5966 54 : case SubscriptionRelationId:
5967 : {
5968 : char *subname;
5969 :
5970 54 : subname = get_subscription_name(object->objectId, missing_ok);
5971 54 : if (subname)
5972 : {
5973 42 : appendStringInfoString(&buffer,
5974 : quote_identifier(subname));
5975 42 : if (objname)
5976 6 : *objname = list_make1(subname);
5977 : }
5978 54 : break;
5979 : }
5980 :
5981 58 : case TransformRelationId:
5982 : {
5983 : Relation transformDesc;
5984 : HeapTuple tup;
5985 : Form_pg_transform transform;
5986 : char *transformLang;
5987 : char *transformType;
5988 :
5989 58 : transformDesc = table_open(TransformRelationId, AccessShareLock);
5990 :
5991 58 : tup = get_catalog_object_by_oid(transformDesc,
5992 : Anum_pg_transform_oid,
5993 : object->objectId);
5994 :
5995 58 : if (!HeapTupleIsValid(tup))
5996 : {
5997 12 : if (!missing_ok)
5998 0 : elog(ERROR, "could not find tuple for transform %u",
5999 : object->objectId);
6000 :
6001 12 : table_close(transformDesc, AccessShareLock);
6002 12 : break;
6003 : }
6004 :
6005 46 : transform = (Form_pg_transform) GETSTRUCT(tup);
6006 :
6007 46 : transformType = format_type_be_qualified(transform->trftype);
6008 46 : transformLang = get_language_name(transform->trflang, false);
6009 :
6010 46 : appendStringInfo(&buffer, "for %s language %s",
6011 : transformType,
6012 : transformLang);
6013 46 : if (objname)
6014 : {
6015 8 : *objname = list_make1(transformType);
6016 8 : *objargs = list_make1(pstrdup(transformLang));
6017 : }
6018 :
6019 46 : table_close(transformDesc, AccessShareLock);
6020 : }
6021 46 : break;
6022 :
6023 0 : default:
6024 0 : elog(ERROR, "unsupported object class: %u", object->classId);
6025 : }
6026 :
6027 7334 : if (!missing_ok)
6028 : {
6029 : /*
6030 : * If a get_object_address() representation was requested, make sure
6031 : * we are providing one. We don't check objargs, because many of the
6032 : * cases above leave it as NIL.
6033 : */
6034 4086 : if (objname && *objname == NIL)
6035 0 : elog(ERROR, "requested object address for unsupported object class %u: text result \"%s\"",
6036 : object->classId, buffer.data);
6037 : }
6038 : else
6039 : {
6040 : /* an empty buffer is equivalent to no object found */
6041 3248 : if (buffer.len == 0)
6042 : {
6043 : Assert((objname == NULL || *objname == NIL) &&
6044 : (objargs == NULL || *objargs == NIL));
6045 510 : return NULL;
6046 : }
6047 : }
6048 :
6049 6824 : return buffer.data;
6050 : }
6051 :
6052 : static void
6053 148 : getOpFamilyIdentity(StringInfo buffer, Oid opfid, List **object,
6054 : bool missing_ok)
6055 : {
6056 : HeapTuple opfTup;
6057 : Form_pg_opfamily opfForm;
6058 : HeapTuple amTup;
6059 : Form_pg_am amForm;
6060 : char *schema;
6061 :
6062 148 : opfTup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfid));
6063 148 : if (!HeapTupleIsValid(opfTup))
6064 : {
6065 12 : if (!missing_ok)
6066 0 : elog(ERROR, "cache lookup failed for opfamily %u", opfid);
6067 12 : return;
6068 : }
6069 136 : opfForm = (Form_pg_opfamily) GETSTRUCT(opfTup);
6070 :
6071 136 : amTup = SearchSysCache1(AMOID, ObjectIdGetDatum(opfForm->opfmethod));
6072 136 : if (!HeapTupleIsValid(amTup))
6073 0 : elog(ERROR, "cache lookup failed for access method %u",
6074 : opfForm->opfmethod);
6075 136 : amForm = (Form_pg_am) GETSTRUCT(amTup);
6076 :
6077 136 : schema = get_namespace_name_or_temp(opfForm->opfnamespace);
6078 136 : appendStringInfo(buffer, "%s USING %s",
6079 : quote_qualified_identifier(schema,
6080 136 : NameStr(opfForm->opfname)),
6081 136 : NameStr(amForm->amname));
6082 :
6083 136 : if (object)
6084 18 : *object = list_make3(pstrdup(NameStr(amForm->amname)),
6085 : pstrdup(schema),
6086 : pstrdup(NameStr(opfForm->opfname)));
6087 :
6088 136 : ReleaseSysCache(amTup);
6089 136 : ReleaseSysCache(opfTup);
6090 : }
6091 :
6092 : /*
6093 : * Append the relation identity (quoted qualified name) to the given
6094 : * StringInfo.
6095 : */
6096 : static void
6097 3350 : getRelationIdentity(StringInfo buffer, Oid relid, List **object,
6098 : bool missing_ok)
6099 : {
6100 : HeapTuple relTup;
6101 : Form_pg_class relForm;
6102 : char *schema;
6103 :
6104 3350 : relTup = SearchSysCache1(RELOID,
6105 : ObjectIdGetDatum(relid));
6106 3350 : if (!HeapTupleIsValid(relTup))
6107 : {
6108 18 : if (!missing_ok)
6109 0 : elog(ERROR, "cache lookup failed for relation %u", relid);
6110 :
6111 18 : if (object)
6112 6 : *object = NIL;
6113 18 : return;
6114 : }
6115 3332 : relForm = (Form_pg_class) GETSTRUCT(relTup);
6116 :
6117 3332 : schema = get_namespace_name_or_temp(relForm->relnamespace);
6118 3332 : appendStringInfoString(buffer,
6119 3332 : quote_qualified_identifier(schema,
6120 3332 : NameStr(relForm->relname)));
6121 3332 : if (object)
6122 2316 : *object = list_make2(schema, pstrdup(NameStr(relForm->relname)));
6123 :
6124 3332 : ReleaseSysCache(relTup);
6125 : }
6126 :
6127 : /*
6128 : * Auxiliary function to build a TEXT array out of a list of C-strings.
6129 : */
6130 : ArrayType *
6131 1686 : strlist_to_textarray(List *list)
6132 : {
6133 : ArrayType *arr;
6134 : Datum *datums;
6135 : bool *nulls;
6136 1686 : int j = 0;
6137 : ListCell *cell;
6138 : MemoryContext memcxt;
6139 : MemoryContext oldcxt;
6140 : int lb[1];
6141 :
6142 : /* Work in a temp context; easier than individually pfree'ing the Datums */
6143 1686 : memcxt = AllocSetContextCreate(CurrentMemoryContext,
6144 : "strlist to array",
6145 : ALLOCSET_DEFAULT_SIZES);
6146 1686 : oldcxt = MemoryContextSwitchTo(memcxt);
6147 :
6148 1686 : datums = (Datum *) palloc(sizeof(Datum) * list_length(list));
6149 1686 : nulls = palloc(sizeof(bool) * list_length(list));
6150 :
6151 4490 : foreach(cell, list)
6152 : {
6153 2804 : char *name = lfirst(cell);
6154 :
6155 2804 : if (name)
6156 : {
6157 2804 : nulls[j] = false;
6158 2804 : datums[j++] = CStringGetTextDatum(name);
6159 : }
6160 : else
6161 0 : nulls[j] = true;
6162 : }
6163 :
6164 1686 : MemoryContextSwitchTo(oldcxt);
6165 :
6166 1686 : lb[0] = 1;
6167 1686 : arr = construct_md_array(datums, nulls, 1, &j,
6168 : lb, TEXTOID, -1, false, TYPALIGN_INT);
6169 :
6170 1686 : MemoryContextDelete(memcxt);
6171 :
6172 1686 : return arr;
6173 : }
6174 :
6175 : /*
6176 : * get_relkind_objtype
6177 : *
6178 : * Return the object type for the relkind given by the caller.
6179 : *
6180 : * If an unexpected relkind is passed, we say OBJECT_TABLE rather than
6181 : * failing. That's because this is mostly used for generating error messages
6182 : * for failed ACL checks on relations, and we'd rather produce a generic
6183 : * message saying "table" than fail entirely.
6184 : */
6185 : ObjectType
6186 1858 : get_relkind_objtype(char relkind)
6187 : {
6188 1858 : switch (relkind)
6189 : {
6190 1404 : case RELKIND_RELATION:
6191 : case RELKIND_PARTITIONED_TABLE:
6192 1404 : return OBJECT_TABLE;
6193 24 : case RELKIND_INDEX:
6194 : case RELKIND_PARTITIONED_INDEX:
6195 24 : return OBJECT_INDEX;
6196 6 : case RELKIND_SEQUENCE:
6197 6 : return OBJECT_SEQUENCE;
6198 404 : case RELKIND_VIEW:
6199 404 : return OBJECT_VIEW;
6200 6 : case RELKIND_MATVIEW:
6201 6 : return OBJECT_MATVIEW;
6202 2 : case RELKIND_FOREIGN_TABLE:
6203 2 : return OBJECT_FOREIGN_TABLE;
6204 12 : case RELKIND_TOASTVALUE:
6205 12 : return OBJECT_TABLE;
6206 0 : default:
6207 : /* Per above, don't raise an error */
6208 0 : return OBJECT_TABLE;
6209 : }
6210 : }
|