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