SQL*Plus 在PL/SQL 编译失败时如何退出

How can I make SQL*Plus exit when PL/SQL compilation fails

我的脚本文件有以下代码:

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 编译错误时退出?

您收到的警告不完全是 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。这意味着实际错误代码将 'wrap',因此它不太可能有意义,但更重要的是,错误代码可能恰好为零 - 这意味着如果您正在检查 return 代码你可能会误以为它是成功的。例如,如果我完成了:

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,那是不相关的。