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