Режимы передачи значений параметров
В PL/SQL есть три режима передачи значений параметров.
Таблица 5. Режимы передачи значений параметров в PL/SQL.
Режим
Предназначение
Использование
IN
только для чтения
переданное значение параметра может читаться, но не может быть изменено внутри процедуры или функции
OUT
для записи
для записи как в неинициализированную переменную (значению параметра внутри процедуры или функции сразу присваивается значение NULL, в дальнейшем оно может изменяться)
IN OUT
для чтения и записи
передается значение, которое можно читать и изменять внутри процедуры или функции
В большинстве случаев параметры передаются в процедуры и функции в режиме IN (именно этот режим используется по умолчанию). Режимы передачи параметров OUT и IN OUT в свою очередь позволяют, например, реализовать возвращение нескольких значений для функции.
Часто функции возвращают код завершения своей работы, который указывается как параметр команды RETURN в теле функции (например, нольуспешное завершение, ненулевое значениеномер ошибки). По смыслу функции получить от нее помимо результата еще что-то, например, диагностическое сообщение с подробностями к коду завершения, невозможно. В команде RETURN может быть указан только один параметр. Выходом является использование формального параметра с режимом передачи OUT. В теле функции следует предусмотреть формирование и запись в этот параметр текстов сообщений, и после каждого вызова функции эти сообщения будут доступны в вызывающем коде в переменных-фактических параметрах.
Основное отличие режима передачи OUT от режима IN OUT заключается в том, что OUT-параметр становится неинициализированным при передаче внутрь процедуры или функции, то есть то значение, которое имела во внешнем блоке переменная-фактический параметр, теряется (становится равным NULL). Это верно во всех случаях, за исключением ситуации, когда внутри процедуры или функции инициируется необработанное в ней исключение. Тогда во внешнем блоке у переменной-фактического параметра для формального OUT-параметра сохранится то ее значение, которое было до передачи. У фактических параметров для формальных IN OUT-параметров значение в NULL не сбрасывается. Если значение фактического параметра внутри программы не меняли, то и после завершения вызова программы оно будет таким же, каким оно было до передачи в программу. Приведем примеры передачи значений параметров в различных режимах.
SQL> CREATE OR REPLACE PROCEDURE test(p1 IN INTEGER,
2 p2 OUT INTEGER,
3 p3 IN OUT INTEGER) IS
4 BEGIN
5 p2 := 11;
6 p3 := 12;
7 END;
8 /
Procedure created.
SQL> DECLARE
2 l_arg1 INTEGER := 5;
3 l_arg2 INTEGER := 6;
4 l_arg3 INTEGER := 7;
5 BEGIN
6 DBMS_OUTPUT.PUT_LINE('before l_arg2='||l_arg2);
7 DBMS_OUTPUT.PUT_LINE('before l_arg3='||l_arg3);
8 test(p1 => l_arg1,p2 => l_arg2,p3 => l_arg3);
9 DBMS_OUTPUT.PUT_LINE('after l_arg2='||l_arg2);
10 DBMS_OUTPUT.PUT_LINE('after l_arg3='||l_arg3);
11 END;
12 /
before l_arg2=6
before l_arg3=6
after l_arg2=11
after l_arg3=12
PL/SQL procedure successfully completed.
Видно, что значение переменной l_arg2, которое было до вызова процедуры test равным 6, внутри процедуры было изменено на 11. Значение переменной l_arg3 после вызова процедуры стало равным 12.
Изменим код процедуры test, заменив ее исполняемый блок пустой командой NULL (то есть с параметрами в коде процедуры никаких действий осуществляться не будет) и вызовем ее еще раз с такими же значениями фактических параметров:
SQL> CREATE OR REPLACE PROCEDURE test(p1 IN INTEGER,
2 p2 OUT INTEGER,
3 p3 IN OUT INTEGER) IS
4 BEGIN
5 NULL;
6 END;
7 /
Procedure created.
SQL> DECLARE
2 l_arg1 INTEGER := 5;
3 l_arg2 INTEGER := 6;
4 l_arg3 INTEGER := 7;
5 BEGIN
6 DBMS_OUTPUT.PUT_LINE('before l_arg2='||l_arg2);
7 DBMS_OUTPUT.PUT_LINE('before l_arg3='||l_arg3);
8 test(p1 => l_arg1,p2 => l_arg2,p3 => l_arg3);
9 DBMS_OUTPUT.PUT_LINE('after l_arg2='||l_arg2);
10 DBMS_OUTPUT.PUT_LINE('after l_arg3='||l_arg3);
11 END;
12 /
before l_arg2=6
before l_arg3=7
after l_arg2=
after l_arg3=7
PL/SQL procedure successfully completed.
Как и ожидалось, значение переменной l_arg2, переданной в процедуру test как OUT-параметр, стало NULL. Значение переменной l_arg3 не изменилось.
Способы передачи значений параметров
Виртуальная машина PL/SQL во время выполнения программ PL/SQL применяет два способа передачи значений параметров:
по ссылкес соответствующим формальным параметром связывается указатель, а не фактическое значение (после этого и формальный и фактический параметры ссылаются на ячейку памяти, содержащую значение параметра);
по значениюзначение фактического параметра копируется в соответствующий формальный параметр (если впоследствии программа завершается без необработанных исключений, то значение формального параметра присваивается обратно фактическому).
Понятно, что для режима передачи значений параметров IN используется передача параметров по ссылке (ведь IN-параметры не изменяются внутри процедур и функций, поэтому значение достаточно только читать по ссылке). Для режимов OUT и IN OUT обычно используется передача по значению.
Ошибки компиляции программ PL/SQL
На практике в большинстве случаев первая попытка откомпилировать программу на языке PL/SQL приводит к получению сообщения о наличии ошибок в ее коде. Чтобы увидеть выявленные компилятором ошибки, можно воспользоваться командой утилиты SQL*Plus SHOW ERRORS. Если команда SHOW ERRORS используется без параметров, то возвращаются ошибки последней компилированной программы.
Создадим процедуру PL/SQL с синтаксической ошибкой (пропущен символ ; после команды NULL):
SQL> CREATE PROCEDURE proc1 AS
2 BEGIN
3 NULL
4 END;
5 /
Warning: Procedure created with compilation errors.
SQL> SHOW ERRORS
Errors for PROCEDURE PROC1:
LINE/COL ERROR
4/1 PLS-00103: Encountered the symbol "END" when expecting one of the
following: ; The symbol ";" was substituted for "END" to continue.
Попробуем создать процедуру c другой ошибкой:
SQL> CREATE OR REPLACE PROCEDURE test(p1 IN INTEGER,
2 p2 OUT INTEGER,
3 p3 IN OUT INTEGER) IS
4 l_p INTEGER := 10;
5 BEGIN
6 p1 := l_p;
7 END;
8 /
Warning: Procedure created with compilation errors.
SQL> SHOW ERRORS
Errors for PROCEDURE TEST:
LINE/COL ERROR
6/3 PL/SQL: Statement ignored
6/3 PLS-00363: expression 'P1' cannot be used as an assignment target
В коде процедуры test имеется семантическая (смысловая) ошибкапопытка изменить значение параметра с режимом передачи IN. Компилятор PL/SQL при анализе кода проверяет отсутствие таких параметров в левой части команд присваивания, в конструкциях SELECT INTO и в других местах кода, где значения таких параметров может быть изменено.
В обоих случаях процедуры proc1 и test как новые объекты базы данных создавались, но с ошибками (Procedure created with compilation errors). Такие объекты базы данных получают статус INVALID и непригодны для использования.
Попытка вызвать процедуру test приведет к ошибке:
SQL> DECLARE
2 l_arg1 INTEGER :=5;
3 l_arg2 INTEGER :=6;
4 l_arg3 INTEGER :=7;
5 BEGIN
6 test(p1 => l_arg1,p2 => l_arg2,p3 => l_arg3);
7 END;
8 /
test(p1 => l_arg1,p2 => l_arg2,p3 => l_arg3);
*
ERROR at line 6:
ORA-06550: line 6, column 3:
PLS-00905: object USER1.TEST is invalid
ORA-06550: line 6, column 3:
PL/SQL: Statement ignored
Хранимая программа PL/SQL может получить статус INVALID как из-за наличия в ее коде синтаксических и семантических ошибок, так и по другим причинам, например, если какие-то объекты базы данных, к которым есть обращения в коде программы, стали недоступными (были удалены, были отозваны привилегии доступа к ним и т. п.).
Отладка программ на PL/SQL
Исправлять ошибки, выявленные компилятором PL/SQL в ходе анализа кода, обычно довольно просто. Для исправления выявленных пользователями ошибок этапа выполнения, следует использовать отладчик PL/SQL. Для удобства отладки можно порекомендовать использовать специализированные средства, например, интегрированную среду разработки Quest SQL Navigator, в которой есть и breakpoints, и watches, и step into, и step overв общем, все средства, достаточные для эффективной отладки программ на процедурном языке программирования.
Для использования отладчика отлаживаемую программу PL/SQL необходимо перекомпилировать с опцией добавления отладочной информации.
SQL> ALTER PROCEDURE insRec COMPILE DEBUG;
Procedure altered.
Редактировать код хранимых программ по опыту авторов также рекомендуется в специализированном Stored Program Editor, который есть в Quest SQL Navigator, TOAD, PL/SQL Developer и Oracle SQL Developer:
после открытия в редакторе исходного текста хранимой программы с ошибками курсор в тексте сразу позиционируется на место ошибки с отображением сообщения об ошибке;