Вызов функции с именем переменной?

У меня есть один пакет с разными процедурами и одна основная процедура, через которую я вызываю другие процедуры.

Через внешний интерфейс я передаю имя процедуры в main(). Есть ли способ вызвать процедуру, просто написав имя параметра, содержащее («Имя процедуры, которое необходимо вызвать»)?

CREATE OR REPLACE PACKAGE BODY UPLOAD_PKG
IS

  --This procedure will populate LOG with messages
  PROCEDURE PRINT_LOG_PR IS
  BEGIN
    fnd_file.put_line(fnd_file.LOG,'ABC');
  END PRINT_LOG_PR;

  --This procedure will populate LOG with messages
  PROCEDURE PRINT_LOG1 IS
  BEGIN
    fnd_file.put_line(fnd_file.LOG, 'XYZ');
  END PRINT_LOG1;

  PROCEDURE Main( p_obj_type VARCHAR2
                 , errbuf VARCHAR2
                 , retcode VARCHAR2) IS
  BEGIN 
    -Is this possible for eg i have passed PRINT_LOG1 here and calling PRINT_LOG1
     p_obj_type ;-
  END main;
END UPLOAD_PKG

person Vineet    schedule 01.10.2010    source источник


Ответы (4)


Да.

PROCEDURE Main( p_obj_type VARCHAR2
              , errbuf VARCHAR2
              , retcode VARCHAR2) IS
BEGIN 
  CASE p_obj_type
  WHEN 'PRINT_LOG_PR' THEN PRINT_LOG_PR;
  WHEN 'PRINT_LOG1' THEN PRINT_LOG1;
  END CASE;
END main;
person Jeffrey Kemp    schedule 01.10.2010

Использовать:

CREATE OR REPLACE PACKAGE BODY UPLOAD_PKG
IS

  --This procedure will populate LOG with messages
  PROCEDURE PRINT_LOG_PR IS
  BEGIN
    fnd_file.put_line(fnd_file.LOG,'ABC');
  END PRINT_LOG_PR;

  --This procedure will populate LOG with messages
  PROCEDURE PRINT_LOG1 IS
  BEGIN
    fnd_file.put_line(fnd_file.LOG, 'XYZ');
  END PRINT_LOG1;

  PROCEDURE MAIN( p_obj_type VARCHAR2
                 , errbuf VARCHAR2
                 , retcode VARCHAR2) IS
  BEGIN 

    CASE p_obj_type
      WHEN 'PRINT_LOG_PR' THEN UPLOAD_PKG.PRINT_LOG_PR;
      WHEN 'PRINT_LOG1' THEN UPLOAD_PKG.PRINT_LOG1;
    END CASE;

  END MAIN;

END UPLOAD_PKG

Оператор CASE, который я использовал в хранимой процедуре MAIN, является оператором PLSQL CASE, а не ANSI SQL CASE. Вы можете сказать, потому что версия PLSQL требует END CASE для завершения оператора CASE.

person OMG Ponies    schedule 01.10.2010
comment
@Джеффри Кемп: Кража! КРАЖА!! :) - person OMG Ponies; 01.10.2010

Если вы не хотите использовать динамический pl/sql, я бы предложил использовать постоянные переменные в заголовке пакета для выбора между процедурами (по возможности избегая жесткого кодирования).

Например, основной вызов процедуры:

UPLOAD_PKG.MAIN(UPLOAD_PKG.C_PRINT_LOG_PR, v_errbuf, v_retcode);

И в основном корпусе вы должны использовать такой случай:

CASE p_obj_type
  WHEN C_PRINT_LOG_PR THEN UPLOAD_PKG.PRINT_LOG_PR;
  WHEN C_PRINT_LOG1   THEN UPLOAD_PKG.PRINT_LOG1;
  ELSE RAISE SOME_ERROR;
END CASE;

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

CREATE OR REPLACE PACKAGE UPLOAD_PKG
IS
  C_PRINT_LOG_PR CONSTANT VARCHAR2(22) := 'What ever';
  C_PRINT_LOG1   CONSTANT VARCHAR2(22) := 'What ever2';
  ...

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

Но для любопытства, не могли бы вы рассказать нам, почему вам нужно использовать package таким образом?

person Jokke Heikkilä    schedule 03.10.2010

Как и решение CASE, это возможно сделать с помощью динамического PL/SQL.

PROCEDURE MAIN( p_obj_type VARCHAR2
             , errbuf VARCHAR2
             , retcode VARCHAR2) IS
 BEGIN 
    EXECUTE IMMEDIATE 'begin upload_pkg.'||p_obj_type|| '; end;';
END MAIN;

Простые параметры (Дата, Varhar2, Число) могут быть переданы IN OUT с помощью команды USING.

Ключевой вопрос заключается в том, является ли это целесообразным.

Как и в случае любого динамического языка, он оставляет место для ошибок, которые будут обнаружены только во время выполнения, а не во время компиляции, т. е. передачи значения для p_obj_type, которого не существует. Вы можете смягчить это с помощью констант или абстрактных типов данных.

Кроме того, каждая динамическая команда sql или pl/sql влечет за собой небольшие накладные расходы на синтаксический анализ по сравнению с фактическим скомпилированным кодом. Эти накладные расходы невелики, но становятся заметными, если выполняются внутри цикла.

Наконец, вызываемый код должен иметь ту же сигнатуру параметра.

person JulesLt    schedule 01.10.2010