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