PageRenderTime 82ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/src/backend/catalog/objectaddress.c

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