Что это значит, когда в теле пакета есть две функции с одинаковым именем, но разными параметрами? - PullRequest
0 голосов
/ 04 апреля 2019

В спецификации пакета имя функции появляется только один раз, поэтому оно не перегружено.В теле пакета одно и то же имя функции появляется дважды с использованием различного набора параметров.Один из них имеет тот же параметр, что и в спецификации пакета.Мой вопрос заключается в том, действительно ли вызывается «первая функция» в теле пакета, и если да, то что именно он делает?Он пытается вернуть себя.

    --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 Ответ

3 голосов
/ 04 апреля 2019

Функция, объявленная в спецификации, является публичной и может быть вызвана извне пакета.Функция, которая определена в теле, но не объявлена ​​в спецификации, является закрытой и может вызываться только из этого пакета.

В вашем примере вторая перегруженная версия вашей функции в теле пакета, которую вы 'он помечен как 'вторая функция', соответствует объявлению в спецификации, так что именно он задействуется при вызове функции из другого места:

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

Мой вопрос в том, является ли «первая функция» втело пакета на самом деле вызывается

Нет.В вашем коде «первая функция» никогда не вызывается.

Она пытается вернуть себя.

Нет, это не так.Ваш 'first func' будет называть 'second func', если он сам был вызван откуда-то еще внутри пакета, но вы в настоящее время этого не делаете.

Отладка там говорит 'вызов первого функционала', но этоэто не так, он вызывает second func, поскольку вызываемый им вызов имеет три аргумента - в соответствии со списком аргументов 'second func'.(Это общедоступно, но это не имеет значения, если это не так, поскольку оно в любом случае является внутренним по отношению к пакету.)

В качестве примера, вы можете вызывать приватную функцию как часть создание и инициализация пакета :

...
  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.

Вы по-прежнему видите тот же вывод FirstOUT_3SecondOUT_3, что и раньше, иззначение 42 передано в этом вызове;но перед этим вы видите вывод FirstOUT_1SecondOUT_1 из 'first func', вызывающего 'second func' со значением 1, как часть этого процесса инициализации.


Разрешено для функции вызывать себя, т.е.рекурсивно, но ему нужно будет каждый раз менять вызов, иначе он застрянет в бесконечном цикле и в конечном итоге будет убит.Вы и здесь этого не делаете.

...