Непоследовательное поведение при выполнении функции из Oracle SQL*Plus?

Я новичок в Oracle и SQL и пытаюсь выполнить простую тестовую функцию из SQL*Plus. Моя функция называется tf (для Test Function) и определяется в файле с именем tf.sql следующим образом;

create or replace
function
tf
(
 arg1 in varchar2
)
return number

as

return_value number;

begin

return_value := 0;
dbms_output.put_line('Argument 1 = ' || arg1);
return return_value;

end;
/

Я могу успешно загрузить эту функцию в Oracle, используя следующую команду;

SQL> start ./tf.sql

В результате выполнения этой команды SQL * Plus просто заявляет;

Function created.

Когда я затем выполняю следующую команду из командной строки SQL * Plus (после того, как я вызвал setoutoutout on);

SQL> exec dbms_output.put_line(SYSTEM.TF('Hello'));

Я получаю следующий вывод;

Argument = Hello
0

PL/SQL procedure successfully completed.

Теперь, если я попытаюсь выполнить свою функцию непосредственно из командной строки SQL * Plus, используя следующую команду;

SQL> exec SYSTEM.TF('Hello');

затем я получаю следующее сообщение об ошибке от SQL*Plus;

BEGIN SYSTEM.TF('Hello'); END;

      *
ERROR at line 1:
ORA-06550: line 1, column 7:
PLS-00221: 'TF' is not a procedure or is undefined
ORA-06550: ;ine 1, column 7
PL/SQL: Statement ignored

Кто-нибудь может пролить свет на это для меня? Я не могу понять, почему моя функция выполняется успешно в первом случае, но не во втором.

Если я выполню следующую команду из командной строки SQL*Plus;

SQL> select * from user_objects where object_name = 'TF';

тогда я получаю следующие результаты;

OBJECT_NAME
-----------
TF
SUBOBJECT_NAME
--------------
OBJECT_ID
---------
74475
DATA_OBJECT_ID
--------------
OBJECT_TYPE
-----------
FUNCTION
CREATED
-------
05-FEB-12
LAST_DDL_
---------
05-FEB-12
TIMESTAMP
---------
2012-02-05:02:11:15
STATUS
------
VALID
T
-
N
G
-
N
S
-
N
EDITION_NAME
------------
1

Любая помощь в этом была бы очень признательна.

Заранее спасибо.

Craig

2 ответа

exec не работает с функциями, потому что не знает, что делать с возвращаемым значением. Это похоже на обычный оператор PL/SQL; если вы вызываете функцию, вы должны присвоить возвращаемое значение чему-либо.

Если вы хотите использовать функцию в SQL*Plus, вы должны использовать вместо этого SQL:

select tf('asdf') from dual;

Кроме того, вы никогда не должны создавать объекты в SYSTEM. Это может вызвать некоторые действительно странные проблемы.

Исходя из ответа @jonearles, который подчеркивает разницу между функцией и процедурой с точки зрения SQL*Plus и комментарием @MS Stp, можно выполнить один из способов:

variable rc number;
exec :rc := tf('Hello');

Argument = Hello

PL/SQL procedure successfully completed.

Чтобы увидеть код возврата, вы можете сделать:

print rc
0

exec на самом деле это просто сокращение для анонимного блока PL/SQL, как вы можете видеть из полученного сообщения об ошибке. variable позволяет объявлять переменную связывания на уровне SQL*Plus, а не в блоке. Вы также можете объявить аргумент как переменную связывания, и установить его с отдельным exec вызов:

variable rc number;
variable arg varchar2(5);
exec :arg := 'Hello';
exec :rc := tf(:arg);

Я часто использую эту конструкцию для тестирования существующего вызова процедуры, например, чего-то, скопированного из кода Pro*C, без необходимости замены переменных в этом вызове фиксированными значениями. Это может упростить повторный вызов с разными аргументами, и вы можете повторно использовать переменные в нескольких вызовах, чтобы вы могли передать :rc к другой функции позже.

Другие вопросы по тегам