当程序包主体中有两个具有相同名称但参数不同的函数时,这意味着什么?

时间:2019-04-04 14:57:16

标签: oracle plsql overloading plsql-package

在软件包规格中,函数名称仅出现一次,因此不会重载。在程序包主体中,相同的函数名称使用不同的参数集出现两次。其中之一的参数与包装规格中的参数相同。我的问题是,包主体中的“第一个函子”是否真正被调用,如果是,它到底在做什么?它试图返回自己。

    --package specification
    CREATE OR REPLACE 
    PACKAGE jtestpkg
      IS
    FUNCTION testfunc(p_num IN NUMBER, p_out1 IN out varchar2, p_out2 IN out varchar2)
      RETURN NUMBER;
    END jtestpkg;

    --package body
    CREATE OR REPLACE 
    PACKAGE BODY jtestpkg
      IS
      --first func
      function testfunc
            (p_num IN NUMBER,
             p_out1 IN OUT varchar2) 
            return number is
                v_out2 varchar2(50);
      BEGIN
      dbms_output.put_line('invoking first func');
          RETURN testfunc(
              p_num,
              p_out1,
              v_out2);
      END;
      --second func
      FUNCTION testfunc(
                p_num IN NUMBER,
                p_out1 IN OUT varchar2,
                p_out2 IN OUT varchar2)
        RETURN NUMBER
        IS
        v_num number;
      BEGIN
        IF 1=p_num THEN
          p_out1:='FirstOUT_1';
          p_out2:='SecondOUT_1';
          dbms_output.put_line(v_num||p_out1||p_out2);
          RETURN 1;
        elsif 2=p_num THEN
          p_out1:='FirstOUT_2';
          p_out2:='SecondOUT_2';
          dbms_output.put_line(v_num||p_out1||p_out2);
          RETURN 2;
        ELSE
          p_out1:='FirstOUT_3';
          p_out2:='SecondOUT_3';
          dbms_output.put_line(v_num||p_out1||p_out2);
          return 3;
        END IF;
        ------
      p_out1:='FirstOUT_0';
      p_out2:='SecondOUT_0';
      dbms_output.put_line(v_num||p_out1||p_out2);
      RETURN 0;
      END testfunc;
    END jtestpkg;

1 个答案:

答案 0 :(得分:3)

规范中声明的函数是公共的,可以从包外部调用。在主体中定义但未在规范中声明的功能是私有的,只能在该程序包内调用。

在您的示例中,包主体中函数的第二个重载版本(已标记为“ second func”)与规范中的声明匹配,因此这是您从其他地方调用函数时涉及的那个版本:

declare
  rc number;
  in_out_1 varchar2(20) := 'A';
  in_out_2 varchar2(20) := 'B';
begin
  rc := jtestpkg.testfunc(42, in_out_1, in_out_2);
end;
/

FirstOUT_3SecondOUT_3


PL/SQL procedure successfully completed.

您体内第一个重载的函数(已标记为“第一个函数”)在规范中没有匹配的声明,因此您不能在外部调用它:

declare
  rc number;
  in_out_1 varchar2(20) := 'A';
begin
  rc := jtestpkg.testfunc(42, in_out_1);
end;
/

ORA-06550: line 5, column 9:
PLS-00306: wrong number or types of arguments in call to 'TESTFUNC'
ORA-06550: line 5, column 3:
PL/SQL: Statement ignored
  

我的问题是,包主体中的“第一个函子”是否真正被调用

不。在您的代码中,永远不会调用“第一个函数”。

  

它试图返回自己。

不,不是。如果您的“第一个函子”本身是从程序包中的其他位置调用的,则将其称为“第二个函子”,但是您目前尚未这样做。

其中的调试显示“调用第一个函数”,但这不是事实,它调用的是 second 函数,因为它进行的调用具有三个参数-与“ second func”参数列表匹配。 (这碰巧是公开的,但是没关系,因为它始终在程序包内部,这无关紧要。)

仅作为示例,您可以在package instantiation and initialization中调用私有函数:

...
  END testfunc;

-- initialization, called on instantiation (for each session)
BEGIN
  dbms_output.put_line('Initialization start');
  declare
    rc number;
    in_out_1 varchar2(20) := 'A';
  begin
    dbms_output.put_line('Initialization: calling first func');
    rc := testfunc(1, in_out_1);
  end;
  dbms_output.put_line('Initialization end');
END jtestpkg;
/

然后在会话中第一次调用程序包中的任何公共实例将其实例化,并对其进行初始化,并运行该程序包级块。因此,使用相同的匿名块:

declare
  rc number;
  in_out_1 varchar2(20) := 'A';
  in_out_2 varchar2(20) := 'B';
begin
  rc := jtestpkg.testfunc(42, in_out_1, in_out_2);
end;
/

您看到的(仅限第一次):

Initialization start
Initialization: calling first func
invoking first func
FirstOUT_1SecondOUT_1
Initialization end
FirstOUT_3SecondOUT_3


PL/SQL procedure successfully completed.

从该调用传递的值42中,您仍然看到与以前相同的FirstOUT_3SecondOUT_3输出;但在此之前,您会看到来自“第一函数”的输出FirstOUT_1SecondOUT_1调用值为1的“第二函数”,作为初始化过程的一部分。


允许一个函数自己进行调用,即递归调用,但是每次都需要更改该调用,否则它将陷入无限循环,并最终被杀死。不过,您在这里也没有这样做。