在复杂的数据库应用开发或迁移过程中,您可能需要在运行时动态获取PL/SQL函数或存储过程的详细定义,例如参数名称、数据类型和模式等。PolarDB PostgreSQL版(兼容Oracle)提供的DBMS_DESCRIBE
内置包能够满足此类需求,它允许您通过程序化方式获取指定PL/SQL对象的元数据信息,并将其存入PL/SQL集合变量中,从而支持动态代码分析、开发调试工具或进行自动化验证。
功能简介
DBMS_DESCRIBE
是一个高度兼容Oracle的内置包,其核心功能由DESCRIBE_PROCEDURE
存储过程提供。当您调用此过程并传入一个PL/SQL对象(如函数或存储过程)的名称时,它会返回该对象所有参数的详细描述信息。
这些返回的信息被存储在多个OUT
参数中,这些参数是基于VARCHAR2_TABLE
和NUMBER_TABLE
两种预定义集合类型(关联数组)的变量。通过遍历这些集合,您可以在PL/SQL代码中访问每个参数的名称、位置、模式(IN/OUT/IN OUT)、数据类型代码等属性。
核心过程:
DBMS_DESCRIBE.DESCRIBE_PROCEDURE
输出数据类型:
TYPE VARCHAR2_TABLE IS TABLE OF VARCHAR2(30) INDEX BY BINARY_INTEGER;
:用于存储字符串类型的参数属性,如参数名。TYPE NUMBER_TABLE IS TABLE OF NUMBER INDEX BY BINARY_INTEGER;
:用于存储数字类型的参数属性,如参数位置、模式、数据类型代码等。
优势
运行时代码分析:允许在PL/SQL程序中动态检查其他函数或过程的接口定义,无需访问静态数据字典。
提升开发效率:可用于构建通用的开发、调试或验证工具,自动化处理与过程调用相关的任务。
适用范围
您的PolarDB PostgreSQL版(兼容Oracle)集群的修订版本需为2.0.14.17.36.0及以上
DESCRIBE_PROCEDURE过程参数
DBMS_DESCRIBE.DESCRIBE_PROCEDURE(
object_name IN VARCHAR2,
reserved1 IN VARCHAR2,
reserved2 IN VARCHAR2,
overload OUT NUMBER_TABLE,
position OUT NUMBER_TABLE,
level OUT NUMBER_TABLE,
argument_name OUT VARCHAR2_TABLE,
datatype OUT NUMBER_TABLE,
default_value OUT NUMBER_TABLE,
in_out OUT NUMBER_TABLE,
length OUT NUMBER_TABLE,
precision OUT NUMBER_TABLE,
scale OUT NUMBER_TABLE,
radix OUT NUMBER_TABLE,
spare OUT NUMBER_TABLE
);
参数 | 类型 | 描述 |
| VARCHAR2 | 必填。要描述的函数或存储过程的名称。
|
| VARCHAR2 | 保留参数,必须设置为 |
| VARCHAR2 | 保留参数,必须设置为 |
| NUMBER_TABLE | 过程的唯一编号,用于区分重载。 说明 此参数在PolarDB中暂未实现,返回值无实际意义。 |
| NUMBER_TABLE | 参数在列表中的位置。 |
| NUMBER_TABLE | 复合类型(如RECORD)的层级。 说明 此参数在PolarDB中暂未实现,返回值无实际意义。 |
| VARCHAR2_TABLE | 函数或存储过程的参数名称。 |
| NUMBER_TABLE | 参数的数据类型代码。 说明 PolarDB返回的是内部数据类型的OID,而非Oracle的类型代码。 |
| NUMBER_TABLE | 参数是否有默认值。 说明 此参数在PolarDB中暂未实现,返回值无实际意义。 |
| NUMBER_TABLE | 参数模式: |
| NUMBER_TABLE | 字符串类型的长度约束。 说明 此参数在PolarDB中暂未实现,返回值无实际意义。 |
| NUMBER_TABLE |
说明 此参数在PolarDB中暂未实现,返回值无实际意义。 |
| NUMBER_TABLE |
说明 此参数在PolarDB中暂未实现,返回值无实际意义。 |
| NUMBER_TABLE |
说明 此参数在PolarDB中暂未实现,返回值无实际意义。 |
| NUMBER_TABLE | 保留字段。 说明 此参数在PolarDB中暂未实现,返回值无实际意义。 |
使用说明
以下示例将演示如何使用DBMS_DESCRIBE.DESCRIBE_PROCEDURE
来获取不同类型PL/SQL对象的参数信息。
数据准备
在执行示例前,请先连接到您的PolarDB PostgreSQL版(兼容Oracle)集群并创建以下测试用的存储过程和包。
-- 1. 创建一个独立的存储过程
CREATE OR REPLACE PROCEDURE standalone_proc(
p_varchar IN VARCHAR2,
p_number OUT NUMBER,
p_date IN OUT DATE
) AS
BEGIN
NULL;
END standalone_proc;
/
-- 2. 创建一个包
CREATE OR REPLACE PACKAGE emp_pkg1 AS
FUNCTION get_employee_name(p_emp_id IN NUMBER) RETURN VARCHAR2;
END emp_pkg1;
/
CREATE OR REPLACE PACKAGE BODY emp_pkg1 AS
FUNCTION get_employee_name(p_emp_id IN NUMBER) RETURN VARCHAR2 IS
BEGIN
RETURN NULL;
END get_employee_name;
END emp_pkg1;
/
-- 3. 创建一个Schema及带Schema的包
CREATE SCHEMA emp_schema;
CREATE OR REPLACE PACKAGE emp_schema.emp_pkg2 AS
FUNCTION get_employee_name(p_emp_id NUMBER) RETURN VARCHAR2;
END emp_pkg2;
/
CREATE OR REPLACE PACKAGE BODY emp_schema.emp_pkg2 AS
FUNCTION get_employee_name(p_emp_id NUMBER) RETURN VARCHAR2 IS
BEGIN
RETURN NULL;
END get_employee_name;
END emp_pkg2;
/
示例1:描述一个独立的存储过程
此示例演示如何获取一个不属于任何包的独立存储过程standalone_proc
的参数信息。
DECLARE
-- 声明用于接收输出的集合变量
v_overload DBMS_DESCRIBE.NUMBER_TABLE;
v_position DBMS_DESCRIBE.NUMBER_TABLE;
v_level DBMS_DESCRIBE.NUMBER_TABLE;
v_arg_name DBMS_DESCRIBE.VARCHAR2_TABLE;
v_datatype DBMS_DESCRIBE.NUMBER_TABLE;
v_default_val DBMS_DESCRIBE.NUMBER_TABLE;
v_in_out DBMS_DESCRIBE.NUMBER_TABLE;
v_length DBMS_DESCRIBE.NUMBER_TABLE;
v_precision DBMS_DESCRIBE.NUMBER_TABLE;
v_scale DBMS_DESCRIBE.NUMBER_TABLE;
v_radix DBMS_DESCRIBE.NUMBER_TABLE;
v_spare DBMS_DESCRIBE.NUMBER_TABLE;
BEGIN
-- 调用过程获取参数信息
DBMS_DESCRIBE.DESCRIBE_PROCEDURE(
object_name => 'standalone_proc',
reserved1 => NULL,
reserved2 => NULL,
overload => v_overload,
position => v_position,
level => v_level,
argument_name => v_arg_name,
datatype => v_datatype,
default_value => v_default_val,
in_out => v_in_out,
length => v_length,
precision => v_precision,
scale => v_scale,
radix => v_radix,
spare => v_spare);
-- 格式化并打印结果
DBMS_OUTPUT.PUT_LINE('Position Name Mode');
DBMS_OUTPUT.PUT_LINE('-------- ----------- ----');
FOR i IN 1..v_arg_name.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(
RPAD(v_position(i), 10) ||
RPAD(NVL(v_arg_name(i), 'N/A'), 13) ||
v_in_out(i)
);
END LOOP;
END;
/
预期输出:
Position Name Mode
-------- ----------- ----
1 p_varchar 0
2 p_number 1
3 p_date 2
示例2:描述包内的函数
此示例演示如何通过package_name.procedure_name
的格式,获取包emp_pkg1
内函数get_employee_name
的参数信息。
DECLARE
v_arg_name DBMS_DESCRIBE.VARCHAR2_TABLE;
v_position DBMS_DESCRIBE.NUMBER_TABLE;
v_in_out DBMS_DESCRIBE.NUMBER_TABLE;
-- 省略其他变量声明以保持简洁
v_overload DBMS_DESCRIBE.NUMBER_TABLE;
v_level DBMS_DESCRIBE.NUMBER_TABLE;
v_datatype DBMS_DESCRIBE.NUMBER_TABLE;
v_default_val DBMS_DESCRIBE.NUMBER_TABLE;
v_length DBMS_DESCRIBE.NUMBER_TABLE;
v_precision DBMS_DESCRIBE.NUMBER_TABLE;
v_scale DBMS_DESCRIBE.NUMBER_TABLE;
v_radix DBMS_DESCRIBE.NUMBER_TABLE;
v_spare DBMS_DESCRIBE.NUMBER_TABLE;
BEGIN
DBMS_DESCRIBE.DESCRIBE_PROCEDURE(
object_name => 'emp_pkg1.get_employee_name',
reserved1 => NULL,
reserved2 => NULL,
overload => v_overload,
position => v_position,
level => v_level,
argument_name => v_arg_name,
datatype => v_datatype,
default_value => v_default_val,
in_out => v_in_out,
length => v_length,
precision => v_precision,
scale => v_scale,
radix => v_radix,
spare => v_spare
);
DBMS_OUTPUT.PUT_LINE('Position Name Mode');
DBMS_OUTPUT.PUT_LINE('-------- ------------- ----');
FOR i IN 1..v_arg_name.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(
RPAD(v_position(i), 10) ||
RPAD(NVL(v_arg_name(i), 'RETURN_VALUE'), 15) || -- 位置0是返回值
v_in_out(i)
);
END LOOP;
END;
/
预期输出:
Position Name Mode
-------- ------------- ----
1 p_emp_id
示例3:描述带Schema的包内函数
此示例演示如何通过schema_name.package_name.procedure_name
的格式,获取特定Schema下包内函数的参数信息。
DECLARE
v_arg_name DBMS_DESCRIBE.VARCHAR2_TABLE;
v_position DBMS_DESCRIBE.NUMBER_TABLE;
v_in_out DBMS_DESCRIBE.NUMBER_TABLE;
-- 省略其他变量声明以保持简洁
v_overload DBMS_DESCRIBE.NUMBER_TABLE;
v_level DBMS_DESCRIBE.NUMBER_TABLE;
v_datatype DBMS_DESCRIBE.NUMBER_TABLE;
v_default_val DBMS_DESCRIBE.NUMBER_TABLE;
v_length DBMS_DESCRIBE.NUMBER_TABLE;
v_precision DBMS_DESCRIBE.NUMBER_TABLE;
v_scale DBMS_DESCRIBE.NUMBER_TABLE;
v_radix DBMS_DESCRIBE.NUMBER_TABLE;
v_spare DBMS_DESCRIBE.NUMBER_TABLE;
BEGIN
DBMS_DESCRIBE.DESCRIBE_PROCEDURE(
object_name => 'emp_schema.emp_pkg2.get_employee_name',
reserved1 => NULL,
reserved2 => NULL,
overload => v_overload,
position => v_position,
level => v_level,
argument_name => v_arg_name,
datatype => v_datatype,
default_value => v_default_val,
in_out => v_in_out,
length => v_length,
precision => v_precision,
scale => v_scale,
radix => v_radix,
spare => v_spare
);
DBMS_OUTPUT.PUT_LINE('Position Name Mode');
DBMS_OUTPUT.PUT_LINE('-------- ------------- ----');
FOR i IN 1..v_arg_name.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(
RPAD(v_position(i), 10) ||
RPAD(NVL(v_arg_name(i), 'RETURN_VALUE'), 15) ||
v_in_out(i)
);
END LOOP;
END;
/
预期输出:
Position Name Mode
-------- ------------- ----
1 p_emp_id