Oracle динамический SQL: UDF внутри выполнить немедленно - PullRequest
0 голосов
/ 12 июня 2019

Я пытаюсь сделать часть своего кода динамической. При наборе вопроса, как использовать UDF в динамическом SQL, я нашел ответ:

Можно позвонить в UDF снаружи!

Это работает:

Update my_table
Set col1 = get_some_value(col2,col2)
Where 1 = 1;

Это не сработало:

Execute Immediate '
Update my_table
Set col1 = get_some_value(col2,col3)
Where 1 = 1
';

Но это работает:

Execute Immediate '
Update my_table
Set col1 = my_package_name.get_some_value(col2,col3)
Where 1 = 1
';

Я использую Oracle Database 12c Enterprise Edition Release 12.1.0.2.0

Если у вас есть идея, как пропустить звонок извне, дайте мне знать.

Множество приветствий, Питер

1 Ответ

0 голосов
/ 12 июня 2019

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

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

Это прекрасно работает в Oracle 12c при входе в систему как владелец схемы:

create function myfunc(p_text in varchar2) return varchar2 is
begin
  return initcap(p_text);
end;
/

begin
  execute immediate 'update emp set ename = myfunc(ename)';
end;
/
select ename from emp;

Возвращает:

King
Blake
Clark
...

EDIT:

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

При использовании execute immediate оператор анализируется и выполняется во время выполнения механизмом Oracle Oracle с очень ограниченным контекстом окружающего кода. Короче говоря, полезная нагрузка execute immediate не знает, что он работает в пакете.

Вот демонстрация, которая должна немного прояснить ситуацию.

create or replace package mytest as
  function public_func(p_text in varchar2) return varchar2;
  procedure demo;
end;
/
create or replace package body mytest as
-------------------------------------------------------------------------------
  function public_func(p_text in varchar2) return varchar2 is
  begin
    return initcap(p_text);
  end;
-------------------------------------------------------------------------------
  function private_func(p_text in varchar2) return varchar2 is
  begin
    return lower(p_text);
  end;
-------------------------------------------------------------------------------
  procedure demo is
  begin
    -- Test 1 should fail because the function name is not fully qualified
    begin
      execute immediate 'update emp set ename = public_func(ename)';
    exception when others then
      dbms_output.put_line('Test1: ' || SQLERRM);
    end;
    -- Test 2 should pass
    begin
      execute immediate 'update emp set ename = mytest.public_func(ename)';
    exception when others then
      dbms_output.put_line('Test2: ' || SQLERRM);
    end;
    -- Test 3 should fail because the private function is not visible
    begin
      execute immediate 'update emp set ename = mytest.private_func(ename)';
    exception when others then
      dbms_output.put_line('Test3: ' || SQLERRM);
    end;
  end;
end;
/

Вот результаты:

SQL> set serveroutput on;
SQL> begin
  2    mytest.demo;
  3  end;
  4  /
Test1: ORA-00904: "PUBLIC_FUNC": invalid identifier
Test3: ORA-00904: "MYTEST"."PRIVATE_FUNC": invalid identifier

PL/SQL procedure successfully completed.

SQL> 

В тесте 1 механизм SQL ищет что-то под названием public_func и не может его найти. Это имеет смысл, потому что вы можете иметь два пакета, в каждом из которых есть что-то с именем public_func. Механизм SQL не знает, что он вызывается из пакета.

Тест 2 - это то, что вы сделали, и он работает как положено.

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

...