#形参和实参

在PL里,参数可区分为形参和实参两个概念。

形参:在定义PL对象时指定的参数,位于头部结构里PL对象名后面的括号中。

实参:在调用PL对象时指定的参数,位于调用时指定的PL对象名后面的括号中。

PL执行器将把实参与形参按照如下三种方式之一进行一一对应:

  • 实参直接输入值或变量,与形参按位置对应。
  • 实参使用"=>"指定形参的名称进行对应。
  • 前两种方式混合,但是在有多个形参时,如果有一个形参对应的实参是按名称指定,则其后的形参对应的实参都要使用按名称方式指定。

如果实参的数据类型与形参不一致,系统会对其进行到形参数据类型的转换,转换规则参考CAST函数描述,如转换失败将抛出错误。

Note

与CAST中将CHAR默认为CHAR(1)不同,在PL中的参数转换无此规则。

示例

--此处的argu称为形参
CREATE OR REPLACE PROCEDURE ya_proc(argu1 FLOAT, argu2 VARCHAR DEFAULT 'shenzhen') AS
BEGIN
DBMS_OUTPUT.PUT_LINE(TO_CHAR(argu1)||'------'||argu2);
END;
/
  
--此处的argu称为实参,该值将被赋给形参
SET NUMWIDTH 20;
exec ya_proc('4');             
  
--result
4.0E+000------shenzhen
  
--无法将实参转换到对应的形参数据类型时,抛出错误
exec ya_proc('shenzhen');             
  
--result
  
YAS-00008 type convert error : not a valid number

# 形参的格式

形参的格式为:参数名称 [参数类型] [NOCOPY] 数据类型 [缺省值]

其中,数据类型里不应该包含长度、精度等属性。

# 形参的类型

包括IN、OUT和IN OUT三种类型。在定义PL对象时,可以为每一个形参显式地指定一个类型,或者不指定而使用默认的IN类型。

# IN参数

IN参数用于向过程体传递一个值,过程体不能修改该参数的值。此时对应的实参可以为常量或变量。

# OUT参数

OUT参数用于向调用器返回一个值。此时对应的实参必须为变量,且实参的值不会被赋给形参,而是过程体执行完成后,将形参值赋给实参用于返回。

# IN OUT参数

IN OUT参数向过程体传递一个初始值,并向调用器返回一个更新后的值。此时对应的实参必须为变量,且实参的值赋给形参,在过程体内部可读可写;过程体执行结束后,将形参值赋给实参用于返回。

# NOCOPY

对于OUT和IN OUT参数类型,可同时指定NOCOPY关键字,该关键字用于语法兼容,无实际含义。

# 形参的缺省值

只能为IN参数指定缺省值,且缺省值需符合该形参的数据类型要求。

对于指定了缺省值的形参,其对应实参可省略,前提是所有指定了缺省值的形参应该定义在括号最后面位置,且应该同时都指定或者都省略,否则不能保证实参对应到正确的形参。但在实参使用"=>"传入参数值时,无需此前提要求。

示例

--创建含三种类型形参的存储过程
CREATE OR REPLACE PROCEDURE ya_proc(
argu_a INT,
argu_b IN INT,
argu_c OUT INT,
argu_d IN OUT BINARY_FLOAT
) IS
BEGIN
DBMS_OUTPUT.PUT_LINE('Inside procedure ya_proc:');
DBMS_OUTPUT.PUT('IN argu_a = ');
DBMS_OUTPUT.PUT_LINE(NVL(TO_CHAR(argu_a), 'NULL'));
DBMS_OUTPUT.PUT('IN argu_b = ');
DBMS_OUTPUT.PUT_LINE(NVL(TO_CHAR(argu_b), 'NULL'));
DBMS_OUTPUT.PUT('OUT argu_c = ');
DBMS_OUTPUT.PUT_LINE(NVL(TO_CHAR(argu_c), 'NULL'));
DBMS_OUTPUT.PUT_LINE('IN OUT argu_d = ' || TO_CHAR(argu_d));
argu_c := argu_a+10;
argu_d := 10/argu_b;
END;
/
  
--创建匿名块调用ya_proc,展示三种类型形参在执行存储过程前、中、后时的值
DECLARE
aa INT := 1;
bb INT := 2;
cc INT := 3;
dd BINARY_FLOAT := 4;
ee INT;
ff BINARY_FLOAT := 5;
BEGIN
DBMS_OUTPUT.PUT_LINE('Before invoking procedure ya_proc:');
DBMS_OUTPUT.PUT('aa = ');
DBMS_OUTPUT.PUT_LINE(NVL(TO_CHAR(aa), 'NULL'));
DBMS_OUTPUT.PUT('bb = ');
DBMS_OUTPUT.PUT_LINE(NVL(TO_CHAR(bb), 'NULL'));
DBMS_OUTPUT.PUT('cc = ');
DBMS_OUTPUT.PUT_LINE(NVL(TO_CHAR(cc), 'NULL'));
DBMS_OUTPUT.PUT_LINE('dd = ' || TO_CHAR(dd));
ya_proc (aa,
bb,
cc,
dd
);
DBMS_OUTPUT.PUT_LINE('After invoking procedure ya_proc:');
DBMS_OUTPUT.PUT('aa = ');
DBMS_OUTPUT.PUT_LINE(NVL(TO_CHAR(aa), 'NULL'));
DBMS_OUTPUT.PUT('bb = ');
DBMS_OUTPUT.PUT_LINE(NVL(TO_CHAR(bb), 'NULL'));
DBMS_OUTPUT.PUT('cc = ');
DBMS_OUTPUT.PUT_LINE(NVL(TO_CHAR(cc), 'NULL'));
DBMS_OUTPUT.PUT_LINE('dd = ' || TO_CHAR(dd));
  
DBMS_OUTPUT.PUT_LINE('Before invoking procedure ya_proc:');
DBMS_OUTPUT.PUT('ee = ');
DBMS_OUTPUT.PUT_LINE(NVL(TO_CHAR(ee), 'NULL'));
DBMS_OUTPUT.PUT_LINE('ff = ' || TO_CHAR(ff));
ya_proc (1,
(bb+3)*4,
ee,
ff
);
DBMS_OUTPUT.PUT_LINE('After invoking procedure ya_proc:');
DBMS_OUTPUT.PUT('ee = ');
DBMS_OUTPUT.PUT_LINE(NVL(TO_CHAR(ee), 'NULL'));
DBMS_OUTPUT.PUT_LINE('ff = ' || TO_CHAR(ff));
END;
/
  
--result
Before invoking procedure ya_proc:
aa = 1
bb = 2
cc = 3
dd = 4.0E+000
Inside procedure ya_proc:
IN argu_a = 1
IN argu_b = 2
OUT argu_c = NULL
IN OUT argu_d = 4.0E+000
After invoking procedure ya_proc:
aa = 1
bb = 2
cc = 11
dd = 5.0E+000
Before invoking procedure ya_proc:
ee = NULL
ff = 5.0E+000
Inside procedure ya_proc:
IN argu_a = 1
IN argu_b = 20
OUT argu_c = NULL
IN OUT argu_d = 5.0E+000
After invoking procedure ya_proc:
ee = 11
ff = 5.0E-001