有关 PL/SQL 包级记录类型的元数据

发布于 2024-12-26 12:02:38 字数 404 浏览 1 评论 0原文

假设您有一个定义了 RECORD 类型的 PL/SQL 包:

CREATE OR REPLACE PACKAGE TEST_PACKAGE AS

    TYPE PERSON_RECORD_TYPE IS RECORD
    (
        first_name VARCHAR2(1000),
        last_name  VARCHAR2(1000)
    );

END;

有没有办法获取 TEST_PACKAGE.PERSON_RECORD_TYPE 中包含的字段列表?例如,是否有包含此信息的 ALL_* 视图?

我对模式级记录类型不感兴趣,只对级记录类型感兴趣。

Suppose you have a PL/SQL package with a RECORD type defined:

CREATE OR REPLACE PACKAGE TEST_PACKAGE AS

    TYPE PERSON_RECORD_TYPE IS RECORD
    (
        first_name VARCHAR2(1000),
        last_name  VARCHAR2(1000)
    );

END;

Is there any way to obtain a list of fields contained within TEST_PACKAGE.PERSON_RECORD_TYPE? For example, are there any ALL_* views with this information?

I am not interested in schema-level record types, only package-level record types.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

南城旧梦 2025-01-02 12:02:38

如果 PERSON_RECORD_TYPE 用作某些过程或函数的参数或结果类型,则可以查询 ALL_ARGUMENTS。信息在那里进行了一点加密(记录和集合的多级封装的层次结构在 POSITION、SEQUENCE 和 DATA_LEVEL 列中进行编码),但它确实存在。

我不认为这样的问题指向错误的架构。对于自动 PLSQL 代码生成,这是完全合法的请求,不幸的是 PLSQL 语言支持非常弱。

If PERSON_RECORD_TYPE is used as argument or result type of some procedure or function, you can query ALL_ARGUMENTS. The information is little bit encrypted there (the hierarchy of multilevel encapsulation of records and collections is encoded in POSITION,SEQUENCE and DATA_LEVEL columns), however it is present.

I don't think such a question points to wrong architecture. For automatic PLSQL code generation this is completely legitimate request, unfortunately with very weak PLSQL language support.

魂牵梦绕锁你心扉 2025-01-02 12:02:38

Oracle 18c 之后的解决方案

我认为这在 18c 之前不起作用(如果我错了,请纠正我),但现在我们可以查询 ALL_PLSQL_TYPE_ATTRS 视图:

SELECT type_name, attr_name, attr_type_name, length
FROM all_plsql_type_attrs
WHERE package_name = 'TEST_PACKAGE'
ORDER BY owner, package_name, type_name, attr_no;

获取某些内容像这样:

TYPE_NAME           ATTR_NAME   ATTR_TYPE_NAME  LENGTH
------------------------------------------------------
PERSON_RECORD_TYPE  FIRST_NAME  VARCHAR2        1000
PERSON_RECORD_TYPE  LAST_NAME   VARCHAR2        1000

Oracle 18c 之前的解决方案

jOOQ 的代码生成器内部使用以下查询来可靠地查找所有包级别PL/SQL RECORD 类型:

SELECT
  "x"."TYPE_OWNER",
  "x"."TYPE_NAME",
  "x"."TYPE_SUBNAME","a".subprogram_id,
  "a"."ARGUMENT_NAME" "ATTR_NAME",
  "a"."SEQUENCE" "ATTR_NO",
  "a"."TYPE_OWNER" "ATTR_TYPE_OWNER",
  nvl2("a"."TYPE_SUBNAME", "a"."TYPE_NAME", NULL) "package_name",
  COALESCE("a"."TYPE_SUBNAME", "a"."TYPE_NAME", "a"."DATA_TYPE") "ATTR_TYPE_NAME",
  "a"."DATA_LENGTH" "LENGTH",
  "a"."DATA_PRECISION" "PRECISION",
  "a"."DATA_SCALE" "SCALE"
FROM "SYS"."ALL_ARGUMENTS" "a"
JOIN (
  SELECT
    "a"."TYPE_OWNER",
    "a"."TYPE_NAME",
    "a"."TYPE_SUBNAME",
    MIN("a"."OWNER") KEEP (DENSE_RANK FIRST
      ORDER BY "a"."OWNER" ASC, "a"."PACKAGE_NAME" ASC, 
               "a"."SUBPROGRAM_ID" ASC, "a"."SEQUENCE" ASC) "OWNER",
    MIN("a"."PACKAGE_NAME") KEEP (DENSE_RANK FIRST
      ORDER BY "a"."OWNER" ASC, "a"."PACKAGE_NAME" ASC, 
               "a"."SUBPROGRAM_ID" ASC, "a"."SEQUENCE" ASC) "PACKAGE_NAME",
    MIN("a"."SUBPROGRAM_ID") KEEP (DENSE_RANK FIRST
      ORDER BY "a"."OWNER" ASC, "a"."PACKAGE_NAME" ASC, 
               "a"."SUBPROGRAM_ID" ASC, "a"."SEQUENCE" ASC) "SUBPROGRAM_ID",
    MIN("a"."SEQUENCE") KEEP (DENSE_RANK FIRST
      ORDER BY "a"."OWNER" ASC, "a"."PACKAGE_NAME" ASC, 
               "a"."SUBPROGRAM_ID" ASC, "a"."SEQUENCE" ASC) "SEQUENCE",
    MIN("next_sibling") KEEP (DENSE_RANK FIRST
      ORDER BY "a"."OWNER" ASC, "a"."PACKAGE_NAME" ASC, 
               "a"."SUBPROGRAM_ID" ASC, "a"."SEQUENCE" ASC) "next_sibling",
    MIN("a"."DATA_LEVEL") KEEP (DENSE_RANK FIRST
      ORDER BY "a"."OWNER" ASC, "a"."PACKAGE_NAME" ASC, 
               "a"."SUBPROGRAM_ID" ASC, "a"."SEQUENCE" ASC) "DATA_LEVEL"
  FROM (
    SELECT
      lead("a"."SEQUENCE", 1, 99999999) OVER (
        PARTITION BY "a"."OWNER", "a"."PACKAGE_NAME", 
                     "a"."SUBPROGRAM_ID", "a"."DATA_LEVEL"
        ORDER BY "a"."SEQUENCE" ASC
      ) "next_sibling",
      "a"."TYPE_OWNER",
      "a"."TYPE_NAME",
      "a"."TYPE_SUBNAME",
      "a"."OWNER",
      "a"."PACKAGE_NAME",
      "a"."SUBPROGRAM_ID",
      "a"."SEQUENCE",
      "a"."DATA_LEVEL",
      "a"."DATA_TYPE"
    FROM "SYS"."ALL_ARGUMENTS" "a"
    WHERE "a"."OWNER" IN ('TEST')     -- Possibly replace schema here
    ) "a"
  WHERE ("a"."TYPE_OWNER" IN ('TEST') -- Possibly replace schema here
  AND "a"."OWNER"         IN ('TEST') -- Possibly replace schema here
  AND "a"."DATA_TYPE"      = 'PL/SQL RECORD')
  GROUP BY
    "a"."TYPE_OWNER",
    "a"."TYPE_NAME",
    "a"."TYPE_SUBNAME"
  ) "x"
ON (("a"."OWNER", "a"."PACKAGE_NAME", "a"."SUBPROGRAM_ID")
 = (("x"."OWNER", "x"."PACKAGE_NAME", "x"."SUBPROGRAM_ID"))
AND "a"."SEQUENCE" BETWEEN "x"."SEQUENCE" AND "next_sibling"
AND "a"."DATA_LEVEL" = ("x"."DATA_LEVEL" + 1))
ORDER BY
  "x"."TYPE_OWNER" ASC,
  "x"."TYPE_NAME" ASC,
  "x"."TYPE_SUBNAME" ASC,
  "a"."SEQUENCE" ASC

在您的情况下,结果将类似于:

TYPE_NAME     TYPE_SUBNAME        ATTR_NAME   ATTR_TYPE_NAME   LENGTH
----------------------------------------------------------------------
TEST_PACKAGE  PERSON_RECORD_TYPE  FIRST_NAME  VARCHAR2         1000
TEST_PACKAGE  PERSON_RECORD_TYPE  LAST_NAME   VARCHAR2         1000

当前限制:

  • 查询将仅查找由至少一种其他类型和/或过程在某处引用的那些类型。这是从查询中的 ALL_ARGUMENTS 字典视图继承的限制。
  • %ROWTYPE 类型未正确返回,因为未从 TYPE_NAME / TYPE_SUBNAME 列引用行类型。

更多信息请点击这里:
https:// blog.jooq.org/2016/11/08/use-jooq-to-read-write-oracle-plsql-record-types

Solution after Oracle 18c

I think this didn't work prior to 18c (correct me if I'm wrong), but now we can query the ALL_PLSQL_TYPE_ATTRS view:

SELECT type_name, attr_name, attr_type_name, length
FROM all_plsql_type_attrs
WHERE package_name = 'TEST_PACKAGE'
ORDER BY owner, package_name, type_name, attr_no;

To get something like this:

TYPE_NAME           ATTR_NAME   ATTR_TYPE_NAME  LENGTH
------------------------------------------------------
PERSON_RECORD_TYPE  FIRST_NAME  VARCHAR2        1000
PERSON_RECORD_TYPE  LAST_NAME   VARCHAR2        1000

Solution prior to Oracle 18c

jOOQ's code generator internally uses the following query to reliably find all package level PL/SQL RECORD types:

SELECT
  "x"."TYPE_OWNER",
  "x"."TYPE_NAME",
  "x"."TYPE_SUBNAME","a".subprogram_id,
  "a"."ARGUMENT_NAME" "ATTR_NAME",
  "a"."SEQUENCE" "ATTR_NO",
  "a"."TYPE_OWNER" "ATTR_TYPE_OWNER",
  nvl2("a"."TYPE_SUBNAME", "a"."TYPE_NAME", NULL) "package_name",
  COALESCE("a"."TYPE_SUBNAME", "a"."TYPE_NAME", "a"."DATA_TYPE") "ATTR_TYPE_NAME",
  "a"."DATA_LENGTH" "LENGTH",
  "a"."DATA_PRECISION" "PRECISION",
  "a"."DATA_SCALE" "SCALE"
FROM "SYS"."ALL_ARGUMENTS" "a"
JOIN (
  SELECT
    "a"."TYPE_OWNER",
    "a"."TYPE_NAME",
    "a"."TYPE_SUBNAME",
    MIN("a"."OWNER") KEEP (DENSE_RANK FIRST
      ORDER BY "a"."OWNER" ASC, "a"."PACKAGE_NAME" ASC, 
               "a"."SUBPROGRAM_ID" ASC, "a"."SEQUENCE" ASC) "OWNER",
    MIN("a"."PACKAGE_NAME") KEEP (DENSE_RANK FIRST
      ORDER BY "a"."OWNER" ASC, "a"."PACKAGE_NAME" ASC, 
               "a"."SUBPROGRAM_ID" ASC, "a"."SEQUENCE" ASC) "PACKAGE_NAME",
    MIN("a"."SUBPROGRAM_ID") KEEP (DENSE_RANK FIRST
      ORDER BY "a"."OWNER" ASC, "a"."PACKAGE_NAME" ASC, 
               "a"."SUBPROGRAM_ID" ASC, "a"."SEQUENCE" ASC) "SUBPROGRAM_ID",
    MIN("a"."SEQUENCE") KEEP (DENSE_RANK FIRST
      ORDER BY "a"."OWNER" ASC, "a"."PACKAGE_NAME" ASC, 
               "a"."SUBPROGRAM_ID" ASC, "a"."SEQUENCE" ASC) "SEQUENCE",
    MIN("next_sibling") KEEP (DENSE_RANK FIRST
      ORDER BY "a"."OWNER" ASC, "a"."PACKAGE_NAME" ASC, 
               "a"."SUBPROGRAM_ID" ASC, "a"."SEQUENCE" ASC) "next_sibling",
    MIN("a"."DATA_LEVEL") KEEP (DENSE_RANK FIRST
      ORDER BY "a"."OWNER" ASC, "a"."PACKAGE_NAME" ASC, 
               "a"."SUBPROGRAM_ID" ASC, "a"."SEQUENCE" ASC) "DATA_LEVEL"
  FROM (
    SELECT
      lead("a"."SEQUENCE", 1, 99999999) OVER (
        PARTITION BY "a"."OWNER", "a"."PACKAGE_NAME", 
                     "a"."SUBPROGRAM_ID", "a"."DATA_LEVEL"
        ORDER BY "a"."SEQUENCE" ASC
      ) "next_sibling",
      "a"."TYPE_OWNER",
      "a"."TYPE_NAME",
      "a"."TYPE_SUBNAME",
      "a"."OWNER",
      "a"."PACKAGE_NAME",
      "a"."SUBPROGRAM_ID",
      "a"."SEQUENCE",
      "a"."DATA_LEVEL",
      "a"."DATA_TYPE"
    FROM "SYS"."ALL_ARGUMENTS" "a"
    WHERE "a"."OWNER" IN ('TEST')     -- Possibly replace schema here
    ) "a"
  WHERE ("a"."TYPE_OWNER" IN ('TEST') -- Possibly replace schema here
  AND "a"."OWNER"         IN ('TEST') -- Possibly replace schema here
  AND "a"."DATA_TYPE"      = 'PL/SQL RECORD')
  GROUP BY
    "a"."TYPE_OWNER",
    "a"."TYPE_NAME",
    "a"."TYPE_SUBNAME"
  ) "x"
ON (("a"."OWNER", "a"."PACKAGE_NAME", "a"."SUBPROGRAM_ID")
 = (("x"."OWNER", "x"."PACKAGE_NAME", "x"."SUBPROGRAM_ID"))
AND "a"."SEQUENCE" BETWEEN "x"."SEQUENCE" AND "next_sibling"
AND "a"."DATA_LEVEL" = ("x"."DATA_LEVEL" + 1))
ORDER BY
  "x"."TYPE_OWNER" ASC,
  "x"."TYPE_NAME" ASC,
  "x"."TYPE_SUBNAME" ASC,
  "a"."SEQUENCE" ASC

In your case, the result will be something like:

TYPE_NAME     TYPE_SUBNAME        ATTR_NAME   ATTR_TYPE_NAME   LENGTH
----------------------------------------------------------------------
TEST_PACKAGE  PERSON_RECORD_TYPE  FIRST_NAME  VARCHAR2         1000
TEST_PACKAGE  PERSON_RECORD_TYPE  LAST_NAME   VARCHAR2         1000

Current limitations:

  • The query will find only those types that are referenced by at least one other type and/or procedure somewhere. This is a limitation inherited from the ALL_ARGUMENTS dictionary view in the query.
  • %ROWTYPE types are not returned correctly because the row type is not referenced from the TYPE_NAME / TYPE_SUBNAME columns.

More information here:
https://blog.jooq.org/2016/11/08/use-jooq-to-read-write-oracle-plsql-record-types

清风不识月 2025-01-02 12:02:38

以下是一些有关从包代码中检索信息的类似问题。

从数据字典中查找包全局变量

从 Oracle 获取包方法和参数

我认为这是一个与第一个类似的问题。您无法通过视图访问这些字段。有解析源文本解决方案,它很丑陋,或者您可能需要解决此问题。

不管怎样,如果你需要这个,我认为你的架构有问题。

Here are some similar questions about retrieving information from package code.

Find package global variables from data dictionary

Get Package Methods and Parameters from Oracle

I see this as a similar problem like first one. You cannot acces those fields via a view. There is the parse source text solution, which is ugly, or you may need an workaround to this.

Anyway, I think it is something wrong in your architecture if you need this.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文