При вызове функции ошибка: 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 шт):

Автор решения: 0xdb

Функции в 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
→ Ссылка
Автор решения: Andrew B

Была ошибка в способе обращения к функции:

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()

Та же ошибка. Пока не победил.

→ Ссылка