Check your grants and make sure you either include explicit schema owner in the quoted call, use a synonym, or connect directly as schema owner.
Remember that stored procedures execute normally with the privileges of the code creator, so you should make certain that the username you use to run the execute immediate has direct grant (not via a role) access to execute the function.
This works fine in Oracle 12c when logged in as schema owner:
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;
Returns:
King
Blake
Clark
...
EDIT:
Based on the additional information that function and calling procedure are in the same package, it is likely that the problem is merely naming and scope.
When using execute immediate
, the statement is parsed and executed at runtime, by Oracle's SQL engine, with very limited context of the surrounding code.
In short, the payload of execute immediate
doesn't know it's running in a package.
Here's a demo that should clear things up a bit.
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;
/
Here's the results:
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>
For test 1, the SQL engine is looking for something called "public_func" and can't find it. This make sense because you could have two packages that each have something called "public_func" in them. The SQL engine does not know that it is being invoked from within a package.
Test 2 is what you did, and it works as expected.
For test 3, a function is called that exists only within the package body. Normally, other procedures in the package can see private functions, but since this is interpreted at runtime and the SQL engine doesn't know it's being called within the scope of the package, this call fails as well.