PL/SQL: есть ли инструкция полностью остановить выполнение script?
Я пытаюсь сделать некоторые проверки в схеме БД в начале PL/SQL script.
Если проверки дают неуспешные результаты, я хочу остановить script, чтобы предотвратить выполнение следующих команд.
У меня есть что-то вроде этого
-- 1st line of PL/SQL script
DECLARE
SOME_COUNT INTEGER;
BEGIN
SELECT COUNT(*) INTO SOME_COUNT FROM SOME_TABLE WHERE <SOME_CONDITIONS>;
IF (SOME_COUNT > 0) THEN
DBMS_OUTPUT.PUT_LINE('Test failed, I don''want the rest of the script'
|| ' to be executed.');
--EXIT or something like that?... <= STOP EXECUTION HERE
END IF;
END;
/
-- OTHER SQL INSTRUCTIONS...
ALTER TABLE SOME_TABLE ...
Я ищу инструкцию (ы), которая позволяет делать "STOP EXECUTION HERE
".
Ответы
Ответ 1
Исходя из вопроса, я не согласен с принятым ответом. В вопросе отображается пакет с несколькими сообщениями script. RAISE_APPLICATION_ERROR() только выходит из блока PL/SQL (подпрограммы), а не из общего script (как указано в Justin), поэтому он будет продолжен с последующими утверждениями.
Для пакетных скриптов лучше использовать WHENEVER SQLERROR EXIT. Да, это директива SQL * Plus, а не стандартный SQL, но довольно портативна; самые популярные инструменты Oracle, которые поддерживают скрипты, поддерживают эту директиву, по крайней мере частично. Следующий пример работает в SQL * Plus, SQL * Developer, Toad, SQLsmith и, возможно, других, и демонстрирует проблему, если вы прокомментируете строку.
set serveroutput on
-- Without this line, things keep going
WHENEVER SQLERROR EXIT SQL.SQLCODE ROLLBACK;
BEGIN
IF (1 > 0) THEN
DBMS_OUTPUT.PUT_LINE('First thing');
RAISE_APPLICATION_ERROR(-20000, 'Test failed'); -- not enough
END IF;
END;
/
-- This will execute if you remove WHEN SQLERROR.., so RAISE_APPLICATION_ERROR is not enough
BEGIN
DBMS_OUTPUT.PUT_LINE('Second thing - Executes anyway');
END;
/
Если вы удалите WHEN SQLERROR, script продолжит и выполнит второй блок и т.д., что именно то, что задает вопрос.
Преимущество в этом случае графических инструментов, которые эмулируют sqlplus, заключается в том, что они действительно останавливают script и не отправляют оставшуюся часть script в командную оболочку в виде команд оболочки, что и происходит если вы вставляете скрипты в SQL * Plus, работающие в окне консоли. SQL * Plus может выйти из строя, но оставшиеся буферизованные команды будут обрабатываться оболочкой ОС, которая является немного беспорядочной и потенциально рискованной, если в комментариях есть команды оболочки (что неслыханно). С SQLPlus всегда лучше всего подключиться, а затем выполнить script или передать его в <start> аргумент командной строки (sqlplus scott/tiger @foo.sql), чтобы избежать этого.
Ответ 2
Если вы не хотите поднимать исключение, вы можете попробовать что-то вроде (untested):
declare
SOME_COUNT INTEGER;
begin
SELECT COUNT(*) INTO SOME_COUNT FROM SOME_TABLE WHERE <SOME_CONDITIONS>;
IF (SOME_COUNT > 0) THEN
DBMS_OUTPUT.PUT_LINE('Test failed, I don''want the rest of the script'
|| ' to be executed.');
goto end_proc;
END IF;
-- A bunch of great code here
<<end_proc>>
null; -- this could be a commit or other lines of code
end;
Некоторые люди ненавидят какие-либо операторы GOTO, поскольку они могут приводить к коду спагетти, если они злоупотребляют, но в простых ситуациях, подобных этому (опять же, если вы не хотите создавать исключение), они хорошо работают imo.
Ответ 3
Несколько секунд поискового запроса дали мне ответ: функция RAISE_APPLICATION_ERROR()
IF (SOME_COUNT > 0) THEN
RAISE_APPLICATION_ERROR(-20000, 'Test failed');
END IF;
Пользовательский код ошибки должен быть между -20000 и -20999.
Подробнее о документе Oracle здесь: http://docs.oracle.com/cd/B10501_01/appdev.920/a96624/07_errs.htm#877 (раздел Определение собственных сообщений об ошибках: процедура RAISE_APPLICATION_ERROR)
Ответ 4
Вместо того, чтобы бросать ошибку приложения, гораздо проще просто использовать RETURN
keyword, который выходит из текущего блока PL/SQL очень плавно.
Просто убедитесь, что вы делаете DBMS_OUTPUT.PUT_LINE('Exited because <error')
перед этим, чтобы предоставить пользователю приятное сообщение о том, почему вы, конечно, выходите!