0

I have read every relevant link on this issue and similar questions/answers, preveland answer is to first set whenever SQLERROR EXIT SQL.SQLCODE; Only then do the query, and then inspect the SQL Plus return code using: ERRORCODE=$?

Here is a sample script:

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`

When ran it debug mode, it gives:

++ 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 ']'

As you can see, returned code is 0! I expected if not 1476, then at least 196 (right most 8 bytes), but not 0 which indicates success!

Please help...

Thanks.

1
  • Provide the full code you ran instead of just a snippet... We can't understand what is happening, and the problem might be in the part of the code you didn't share. Commented Jun 20, 2016 at 13:12

1 Answer 1

4

Your ERRORCODE is being set to zero because that's the exit code from the subshell you're running SQL*Plus is, viq the backticks. The exit code of the SQL*Plus process is 196 but you aren't capturing that, and it's not that easy to do that within a heredoc. The stdout from the process - which is what you are capturing - is not that exit code, it's the query and error message being printed. And even if you could capture it, I'm not sure how you'd distinguish between the 196 coming from an error, or from your actual query.

You could do something like running the query in a block that hides the error and prints either a default value or the actual calculated value, or only look at the last line of output and try to interpret that; but you'll still be fighting against it showing the command being run. SQL*Plus has set echo off but that doesn't do anything with an interactive session, which this still is with input redirection.

Another way to go is to create a script file and temporarily store the output:

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

This creates a (process-specific) .sql file; executes that write the output (minus the statement, via set echo off) to a .out file; checks the SQL*Plus exit code; and if that is zero gets the result from the file.

As you hinted relying on SQL.SQLCODE to detect an error from your shell script is dangerous as you could get an error that wraps to zero, so I've used the generic FAILURE. If you need the real error code you can get it from the output file.


Another approach using a PL/SQL block:

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=$?

If the PL/SQL block runs then ERRORCODE will be zero and CHUNK_AMOUNT will be the calculated value if it's successful, or the SQL code if it throws an exception; since that will be negative (-1476 in your example) you can test that to see if it's expected, if you're only expecting positive values.

If the block can't run because of a syntax error or invalid credentials (notice the -l flag I snuck in) then ERRORCODE will be 1 and CHUNK_AMOUNT will have the error text, e.g. ERROR: ORA-12154: TNS:could not resolve the connect identifier... or whatever actually went wrong. The set -f stops a * in the error message being expanded into a file list from the current directory.

Or even more simply and closer to your original:

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=$?

and now ERRORCODE is 0 on success and CHUNK_AMOUNT has the calculated value on any error ERRORCODE is 1, you can test that directly, and the actual error is always in CHUNK_AMOUNT - but only as a string, you don't get -1476 this way.

Sign up to request clarification or add additional context in comments.

4 Comments

Awesome! looks good, I am going to test it soon, but I am concerned about performance. This is needed for conversion process which will run mililons of times (not this specific query, but others in the process will be) - if each writes to disk and reads twice, it will significantly slow down the time to complete conversion. Any workarounds to writing this down on HDD?
@Carmageddon - added two none-disk versions. I think the last is simplest and will work for what you're doing. Depends whether you want CHUNKSIZE to ever hold just the (negative) SQL code.
Thank you very much! the last one will work perfectly for most of the simpler queries, and PL/SQL blocks for the more complicated ones. BTW: its CHUNK_AMOUNT not CHUNKSIZE, please edit so it won't confuse anyone else in the future.
@Alex, i tried your solution and I was able to get the error and proper exit code but when I changed my SQL to an update which was violating an integrity constraint (ORA-02291). the exit code is still 0 and there is no error message in the output file. Do you know what might be different in that case. I posted a question few days back here. This question is using heredoc.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.