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