【问题标题】:Error Handling of SQLPlus from Bash - not working来自 Bash 的 SQLPlus 错误处理 - 不起作用
【发布时间】:2016-10-21 17:26:25
【问题描述】:

我已阅读有关此问题和类似问题/答案的所有相关链接,preveland 答案是首先设置whenever SQLERROR EXIT SQL.SQLCODE; 然后才进行查询,然后使用以下命令检查 SQL Plus 返回码:ERRORCODE=$?

这是一个示例脚本:

GetAmountOfChunks()
{
 export CHUNK_AMOUNT=`sqlplus -s $CONSTR<<SQL
    set heading off;
     set trim on;
     set feed off;
     whenever SQLERROR EXIT SQL.SQLCODE;
     select 1/0 from dual;
     --SELECT COUNT(*) FROM CNV_CHUNKS_PROC_STATUS;
     /
SQL`

当运行它的调试模式时,它给出:

++ sqlplus -s USER/PASS@HOST/DB
+ export 'CHUNK_AMOUNT=     select 1/0 from dual
                      *
ERROR at line 1:
ORA-01476: divisor is equal to zero'
+ CHUNK_AMOUNT='     select 1/0 from dual
                      *
ERROR at line 1:
ORA-01476: divisor is equal to zero'
+ ERRORCODE=0
+ '[' 0 -ne 0 ']'

如您所见,返回码为 0! 我预计如果不是 1476,那么至少是 196(最右边 8 个字节),但不是 0,表示成功!

请帮忙...

谢谢。

【问题讨论】:

  • 提供您运行的完整代码,而不仅仅是一个 sn-p... 我们无法理解发生了什么,问题可能出在您未共享的代码部分。

标签: oracle bash sh sqlplus ksh


【解决方案1】:

您的ERRORCODE 被设置为零,因为这是您运行SQL*Plus 的子shell 的退出代码,viq 是反引号。 SQL*Plus 进程的退出代码是 196,但您没有捕捉到它,而且在 heredoc 中做到这一点并不容易。过程中的标准输出(您正在捕获的内容)不是退出代码,而是正在打印的查询和错误消息。即使您可以捕获它,我也不确定您如何区分来自错误或实际查询的 196。

您可以执行一些操作,例如在隐藏错误并打印默认值或实际计算值的块中运行查询,或者只查看输出的最后一行并尝试解释它;但你仍然会反对它显示正在运行的命令。 SQL*Plus 有 set echo off 但这对交互式会话没有任何作用,这仍然是输入重定向。

另一种方法是创建一个脚本文件并临时存储输出:

echo "
    set pages 0
    set trim on
    set feed off
    set echo off
    whenever SQLERROR EXIT FAILURE
    select 1/0 from dual;
    --SELECT COUNT(*) FROM CNV_CHUNKS_PROC_STATUS;
    exit 0;
" > /tmp/GetAmountOfChunks_$$.sql
sqlplus -s -l $CONSTR @/tmp/GetAmountOfChunks_$$.sql > /tmp/GetAmountOfChunks_$$.out
if [[ $? -eq 0 ]]; then
  export CHUNK_AMOUNT=`cat /tmp/GetAmountOfChunks_$$.out`
else
  # whatever you want to do on error; show output file? set default?
  cat /tmp/GetAmountOfChunks_$$.out
fi

rm -f /tmp/GetAmountOfChunks_$$.sql /tmp/GetAmountOfChunks_$$.out

这会创建一个(特定于进程的).sql 文件;执行将输出(减去语句,通过set echo off)写入.out 文件;检查 SQL*Plus 退出代码;如果为零,则从文件中获取结果。

正如您所暗示的那样,依靠SQL.SQLCODE 从您的 shell 脚本中检测错误是很危险的,因为您可能会得到一个归零的错误,所以我使用了通用的FAILURE。如果您需要真正的错误代码,可以从输出文件中获取。


使用 PL/SQL 块的另一种方法:

set -f
CHUNK_AMOUNT=`sqlplus -s $CONSTR <<SQL
    set heading off;
    set trim on;
    set feed off;
    whenever SQLERROR EXIT FAILURE;
    set serveroutput on;
    declare
      chunk_amount number;
    begin
      select 1/0 into chunk_amount from dual;
      --SELECT COUNT(*) INTO chunk_amount FROM CNV_CHUNKS_PROC_STATUS;
      dbms_output.put_line(chunk_amount);
    exception
      when others then
        dbms_output.put_line(sqlcode);
    end;
    /
    exit 0
SQL
exit $?`
ERRORCODE=$?

如果 PL/SQL 块运行,则 ERRORCODE 将为零,如果成功,CHUNK_AMOUNT 将是计算值,如果抛出异常,则为 SQL 代码;因为这将是负数(在您的示例中为 -1476),您可以对其进行测试以查看它是否符合预期,如果您只期望正值。

如果由于语法错误或无效凭据而无法运行块(请注意我潜入的-l 标志),则ERRORCODE 将为1,CHUNK_AMOUNT 将显示错误文本,例如ERROR: ORA-12154: TNS:could not resolve the connect identifier... 或任何实际出错的地方。 set -f 阻止错误消息中的 * 从当前目录扩展为文件列表。

或者更简单,更接近您的原作:

set -f
CHUNK_AMOUNT=`sqlplus -s $CONSTR <<SQL
    set heading off;
    set trim on;
    set feed off;
    whenever SQLERROR EXIT FAILURE;
    select 1/0 from dual;
    --SELECT COUNT(*) FROM CNV_CHUNKS_PROC_STATUS;
    exit 0
SQL
exit $?`
ERRORCODE=$?

现在ERRORCODE 成功时为 0,CHUNK_AMOUNT 有任何错误的计算值 ERRORCODE 为 1,您可以直接测试,实际错误始终在 CHUNK_AMOUNT - 但仅作为字符串,这样你不会得到 -1476。

【讨论】:

  • 太棒了!看起来不错,我很快就会测试它,但我担心性能。这对于将运行数百万次的转换过程是必需的(不是这个特定的查询,而是过程中的其他查询) - 如果每个写入磁盘并读取两次,它将显着减慢完成转换的时间。有什么办法可以在硬盘上写下来?
  • @Carmageddon - 添加了两个无磁盘版本。我认为最后一个是最简单的,并且适用于您正在做的事情。取决于您是否希望 CHUNKSIZE 只保留(负)SQL 代码。
  • 非常感谢!最后一个对于大多数更简单的查询非常有效,而对于更复杂的查询则使用 PL/SQL 块。顺便说一句:它的 CHUNK_AMOUNT 不是 CHUNKSIZE,请编辑,以免将来混淆其他人。
  • @Alex,我尝试了您的解决方案,并且能够得到错误和正确的退出代码,但是当我将 SQL 更改为违反完整性约束的更新时 (ORA-02291)。退出代码仍为 0,并且输出文件中没有错误消息。你知道在这种情况下可能会有什么不同吗?几天前我发布了一个问题here。本题使用的是heredoc。
猜你喜欢
  • 2014-01-18
  • 2018-10-07
  • 2017-04-07
  • 2015-07-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-11
相关资源
最近更新 更多