При вызове функции ошибка: PLS-00221: 'function_name' is not a procedure or is undefined
Необходимо в скрипте вызвать пользовательскую функцию, которая возвращает строку VARCHAR2.
function f_check_source return varchar2 is
not_in_source varchar2(2000);
not_in_target varchar2(2000);
sql_stmt varchar2(4000);
v_out varchar2(4000);
begin
sql_stmt := 'select ''1'' not_in_target, ''2'' not_in_source from dual';
execute immediate sql_stmt into not_in_target, not_in_source ;
v_out := 'not_in_source: '||not_in_source||Chr(13)||Chr(10)||'not_in_target: '||not_in_target;
return v_out;
end f_check_source;
import sqlalchemy as sa
db_source_user = 'user'
db_source_passw = 'passw'
db_source_sid = 'sid'
cstr = 'oracle://{user}:{password}@{sid}'.format(
user=db_source_user,
password=db_source_passw,
sid=db_source_sid
)
engine = sa.create_engine(cstr)
connection = engine.connect()
# some code
v_out = connection.execute('begin shema.package_name.function_name(without paramemetes); end;')
# v_out = v_out.fetchone()
print(v_out)
Получаю ошибку:
PLS-00221: 'function_name' is not a procedure or is undefined
Что не так делаю?
P.S. Гуглил, но что-то предложенные решения не помогли, ну или что-то не понял. SQLAclcheme только пробую использовать.
Ответы (2 шт):
Функции в PL/SQL не могут возвращать результат в "никуда", что имеет место в других ЯП.
Вот так работать не будет:
create package pack is function foo return int;
end;
/
create package body pack is
function foo return int is begin return 0; end;
end;
/
begin pack.foo; end;
/
ORA-06550: line 1, column 7:
PLS-00221: 'FOO' is not a procedure or is undefined
Функция должна быть вызвана внутри выражения, которое может принять её результат.
Об этом и сообщает компилятор в сообщении об ошибке - он пытается найти процедуру, потому что её вызов это законченое выражение.
Или просто в SQL запросе:
select pack.foo res from dual
/
RES
--------
0
Или с переменной связывания в анонимном блоке:
var res number
begin :res := pack.foo; end;
/
print res
RES
--------
0
Была ошибка в способе обращения к функции:
import sqlalchemy as sa
db_source_user = 'user'
db_source_passw = 'passw'
db_source_sid = 'sid'
cstr = 'oracle://{user}:{password}@{sid}'.format(
user=db_source_user,
password=db_source_passw,
sid=db_source_sid
)
engine = sa.create_engine(cstr)
connection = engine.connect()
# some code
v_out = connection.execute('select shema.package_name.function_name from dual;').fetchone()
v_out = v_out._data[0]
print(v_out)
P.S. спасибо 0xdb за то. что обратил внимание.
Но у этого способа есть нюанс. DML операции нельзя вызывать из DDL, соответственно если вызываемая функция исполняет команду DML, в execute() нам нужно использовать анонимный блок. И вот тут вопрос как вернуть из функции с DML значение. При попытке обращаться к функции:
connection.execute(declare x number; begin x := shema.package_name.function_name; end;).fetchone()
{ResourceClosedError}This result object does not return rows. It has been closed automatically.
Переписал в процедуру, которая на выходе дает SYS_REFCIRSOR/фиддл
connection.execute('declare res sys_refcursor; begin shema.package_name.procedure_name(res); end;').fetchone()
Та же ошибка. Пока не победил.