PL/SQL 编译失败时如何让 SQL*Plus 退出
Posted
技术标签:
【中文标题】PL/SQL 编译失败时如何让 SQL*Plus 退出【英文标题】:How can I make SQL*Plus exit when PL/SQL compilation fails 【发布时间】:2016-03-09 21:32:42 【问题描述】:我的脚本文件有以下代码:
WHENEVER SQLERROR EXIT SQL.SQLCODE
@pkg_t.pks
@pkg_t.pkb
我正在从 SQL*Plus 运行该脚本。如果pkg_t.pkb
无效,我会看到:
Warning: Package created with compilation errors.
但 SQL*Plus 不退出。我了解到pkg_t.pkb
有一个 PL/SQL 错误编译,它与 SQL 错误不同。
需要添加什么指令让SQL*Plus在遇到PL/SQL编译错误时退出?
【问题讨论】:
【参考方案1】:您收到的警告并不完全是 PL/SQL 错误或 SQL 错误。 PL/SQL 运行时错误会导致类似 ORA-06550 的问题,您的 whenever sqlerror
会捕获该错误,并且脚本将使用该代码退出。但是,您会看到一个编译错误,这是不同的,它是由客户端生成的。
捕获它的一种方法是检查存储在数据字典中的错误:
WHENEVER SQLERROR EXIT SQL.SQLCODE
@pkg_t.pks
@pkg_t.pkb
declare
l_errors pls_integer;
begin
select count(*) into l_errors from user_errors;
if l_errors > 0 then
raise_application_error(-20001, 'Stored PL/SQL has compilation errors');
end if;
end;
/
exit 0;
如果包规范或正文出现错误,则计数将非零,您将看到:
declare
*
ERROR at line 1:
ORA-20001: Stored PL/SQL has compilation errors
ORA-06512: at line 6
您还可以在user_objects
中检查对象状态。如果你想检查一个特定的对象,你可以命名它,但这会降低它的灵活性;如果您预计周围还有其他现有的无效对象,则可能需要这样做。保持其通用性意味着您可以拥有一个单独的脚本,您可以重复调用该脚本以尽早捕获错误,例如 check_errors.sql
仅包含:
declare
l_errors pls_integer;
begin
select count(*) into l_errors from user_errors;
if l_errors > 0 then
raise_application_error(-20001, 'Stored PL/SQL has compilation errors');
end if;
end;
/
然后你可以这样做:
@pkg_t.pks
@check_errors
@pkg_t.pkb
@check_errors
当然,您可以使脚本更精美,并进行其他检查。如果您现有的 .pks 和 .pkb 脚本还没有这样做,您可以添加 show errors
以便查看实际问题。
关于SQL.SQLCODE
的旁注。那将有实际的错误代码,例如6550 或 20001。但大多数 shell 只允许错误代码达到较小的值,例如127 或 255。这意味着实际的错误代码将“换行”,因此它不太可能有意义,但更重要的是,可能有一个错误代码恰好换行为零 - 这意味着如果您正在检查返回代码,您可能会错误地认为它是成功的。例如,如果我完成了:
raise_application_error(-20224, 'Stored PL/SQL has compilation errors');
然后 -20224 值将归零; SQL*Plus 将退出该代码,但如果我在 bash 中检查$?
,它将是0
,并且看起来它已经成功了。类似地,-20223 会换行到 255,-20225 会换行到 1 - bash 会将两者都视为错误,但不会指出实际错误是什么。
所以使用固定值会更安全。我经常只使用whenever sql error exit failure
,通常会添加rollback
,但如果你只是在做DDL,那就没关系了。
【讨论】:
check_errors 显示所有错误,目前尚未修复。有没有办法只看到由以前的脚本引起的那些?我想以某种方式重置 user_errors。 @GerritGriebel - 不是真的。我能想到的唯一方法是将脚本开始时间记录为变量,然后在该点之后查找创建或修改的对象(last_ddl_time)的错误,将 user_objects 加入 user_errors。不过,这有点超出范围;也许尝试一下,如果你不能让它工作,请提出一个新问题?以上是关于PL/SQL 编译失败时如何让 SQL*Plus 退出的主要内容,如果未能解决你的问题,请参考以下文章
如何在 PL/SQL 中使用 select 语句为 SQL*Plus 变量赋值?