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