x31forest has asked for the wisdom of the Perl Monks concerning the following question:

Hey monks,
I'm having some troubles capturing errors from some sql scripts that i'm running and looking for some ideas.

Right now I'm running  system("sqlplus user/pass \@test.sql")
This works and it's running but I can't seem to retrieve any errors from it. The $? variable always returns 0(success). Test.sql contains a list of sqlplus commands.

Any other way of doing it ? I wouldn't like to take every SQL command out of the test.sql file and run it through DBI. Would capturing the output from system and grepping for ERROR work for all cases ? Thanks monks, -Paul

Replies are listed 'Best First'.
Re: sqlplus or DBI
by insensate (Hermit) on Nov 18, 2002 at 21:13 UTC
    Typically when calling sqlplus scripts from any outside program... be it Perl or Shell... I wrap the sql commands in the following:
    whenever SQLERROR exit SQL.SQLCODE set feeback off set verify off set lines 32 set pages 0 set linesize 500 set tab off * your script exit SQL.SQLCODE *SQLPlus often formats white space in output using tab characters, not + spaces... "set tab off" prevents this
    You probably also want to use the -s switch to use silent mode. After implementing this, you can say:
    $result=`sqlplus -s user/pass \@myfile`; if($result=~/(?:SP2|ORA)/){ print "SQL ERROR: $result\n"; }

      Ooh, no! You don't want to do that!

      The system status code is only one byte wide, and so can only handle values in the range 0 to 255. Picking a random example, do you know what error code 244 refers to? Yes, that's right: "integrity constraint (%s.%s) violated - child record found"

      The point here is that the particular error I've quoted above is actually code 2292, which any good mod function can tell you is 256*8+244. The multiples of 256 get thrown away by the operating system.

      Now, what do you think happens if you get the error "space quota exceeded for tablespace '%s'"? Yes, that's right: it's code 1536, which is exactly 256*6. And the system neatly truncates this to 0.

      Actually, the best solution I found was to use WHENEVER ERROR EXIT 2, and terminate the script with EXIT 1. That way, you can tell if the script never started (exit code 0), completed successfully (code 1), or failed (code 2).

      --
      Tommy
      Too stupid to live.
      Too stubborn to die.

        Remember that using backticks to execute a call is not the same as using system(). The latter returns the exit status...the former the output of the call. So when I call a sql script that will exit with sql.sqlerror and it fails with ORA-2292... the errorcode will indeed be the value in $result as long as it is called with backticks or qx//.
        Jason
Re: sqlplus or DBI
by fruiture (Curate) on Nov 18, 2002 at 18:23 UTC

    system() is not the right function for the purpose of capturing output. Consider qx// (aka `backticks`) or open() for that job.

    I don't know if grepping for "ERROR" in the command's STDOUT would suffice, you should be able to specify that ;)

    open my $pipe , '-|' , 'sqlplus user/pass @test.sql' or die "hmm? $!"; while( <$pipe> ){ print if /error/i } close $pipe or die "hmhmm? $!";
    --
    http://fruiture.de
Re: sqlplus or DBI
by metadatum (Scribe) on Nov 18, 2002 at 18:19 UTC
    the system call returns an error code -- and thats all.
    If you want to be able to parse the output, use backticks:
    @results = `sqlplus user/pass \@test.sql`;
      Yea but the error code is not correct. Even if I have errors in my sql, it still returns 0, success.
      What would I be parsing the output for ?
      thanks,
Re: sqlplus or DBI
by x31forest (Novice) on Nov 18, 2002 at 18:38 UTC
    Found something usefull on google groups just now.

    Adding whenever sqlerror exit failure to my sql makes sqlplus return an error code > 0. So I'll be using that untill i hear of something better.
    Any way I can do the same thing using DBI ?

    thanks,
    Paul

      Yes, you can do the same thing with DBI. It would be even better...

      The easy way ist to slurp the sql-commands-file and directly submit it to $dbh->prepare( $commands )->execute

      Mor advanced would be to parse the SQL beforehand and submit the queries one after the other. In fact, you only have to split on semicolon, except semicolons in quotes.

      --
      http://fruiture.de
Re: sqlplus or DBI
by UnderMine (Friar) on Nov 19, 2002 at 15:02 UTC
    I am currious to see the script as generally you should not need to do that

    try :-

    $/='/'; while (<FILE>) { # process and return errors }
    This assumes you are seperating your commands with '/' execution which is usual in oracle.

    Hope this helps
    UnderMine