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