Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I exit a script in SQLPlus when an error occurs and return to the SQLPlus prompt, without disconnecting or exiting SQLPlus?

Tags:

oracle

sqlplus

I have some scripts that get run often, always from within a connected SQLPlus session.

I need a way to exit the script when an error occurs, without disconnecting or exiting SQLPlus itself. 100% of the time, when an error occurs, the connected DBA will need to issue one or more commands into the session. 100% of the time, when an error occurs, there are other SQLPlus statements (and thus must be outside of a BEGIN..END;) later on in the script that must not be executed or serious problems could arise.

NOTE: If you suggest WHENEVER SQLERROR EXIT then you didn't read the above text. That will disconnect and exit SQLPlus in addition to the script, which is not acceptable behavior.

like image 895
Thought Avatar asked Jun 25 '12 20:06

Thought


3 Answers

I've found an interesting idea here which, when combined with spencer7593's answer, will get me selective sub-script calling, to which I can pass the PL/SQL output values. To wit:

VAR continue number;
EXEC :continue := 1;
BEGIN
   SELECT some_bool_test() INTO :continue FROM dual;
END;

SET termout OFF
COLUMN script_name NEW_VALUE v_script_name
SELECT decode(:continue, 1, 'run_stuff.sql', 'skip.sql') script_name FROM dual;
SET termout ON

@&v_script_name :some_other_values

Where skip.sql is an empty text file.
 

UPDATE: I've moved most of this into a RUN.SQL file, where I pass in the boolean (0 or 1) as &1, the script name to call on success as &2, and then any other expected parameters to pass to the called script. Thus, it ends up looking something like this:

VAR continue number;
EXEC :continue := 1;
BEGIN
   SELECT some_bool_test() INTO :continue FROM dual;
END;

@run.sql :continue 'run_stuff.sql' :some_other_values
like image 108
Thought Avatar answered Oct 26 '22 17:10

Thought


It's not possible.

SQLPlus doesn't provide that level of control over the execution of a script.

Obviously, you'd need to AVOID using the WHENEVER SQLERROR EXIT ... command.

It's possible to gain conditional control over which SQL statements do or do not get executed as a result of raised exceptions (errors) using PL/SQL. But that doesn't address SQLPlus commands (which cannot be executed from within a PL/SQL block.)

DECLARE
  lb_continue BOOLEAN;
BEGIN
  lb_continue := TRUE;
  BEGIN 

    sql statement

  EXCEPTION
    WHEN OTHERS THEN
      lb_continue = FALSE;
  END;
  IF lb_continue THEN
  BEGIN

    sql statements

  EXCEPTION
    WHEN OTHERS THEN
      lb_continue := FALSE;
  END; 
END;

Of course, that approach has it's own limitations and issues. Any DDL statements would need to be called dynamically; the easiest way to do that is an EXECUTE IMMEDIATE statement.

The biggest issue (in your case) is that it's not possible to execute SQLPlus commands from inside a PL/SQL block.

like image 41
spencer7593 Avatar answered Oct 26 '22 17:10

spencer7593


You can't exit the script and stay in SQL*Plus, but you can stop executing things. It isn't pretty, but assuming you can modify the script to add the control flow then you can just about do this with bind variable.

set serveroutput on

var flag char;
exec :flag := 'Y';

begin
    if :flag != 'Y' then
        raise program_error;
    end if;
    dbms_output.put_line('Doing some work');
    /* Check for some error condition */
    if 0 != 1 then
        raise program_error;
    end if;
    /* Only reach this if earlier statements didn't fail
     * but could wrap in another flag check if needed */
    dbms_output.put_line('Doing some more work');
    exception
        when program_error then
            dbms_output.put_line(sqlerrm);
            :flag := 'N';
        when others then
            /* Real exception handling, obviously */
            dbms_output.put_line(sqlerrm);    
            :flag := 'N';
end;
/

-- DML only does anything if flag stayed Y
select sysdate from dual
where :flag = 'Y';

-- Optional status message at the end of the script, for DBA info
set feedback off
set head off
select 'Something went wrong' from dual where :flag != 'Y';
set feedback on
set head on

When executed:

SQL> @script

PL/SQL procedure successfully completed.

Doing some work
ORA-06501: PL/SQL: program error

PL/SQL procedure successfully completed.


no rows selected


Something went wrong
SQL> 

Any PL/SQL blocks in the script can check the flag status at the start, and raise program_error (just as a handy pre-defined exception) to jump back out. Anything that errors inside a PL/SQL block can update the bind variable flag, either directly or in an exception handler. And any non-PL/SQL DML can have an additional where clause to check the flag status, so if it's been set to N by the time that statement is reached, no work is done. (For an insert I guess that would mean not using the values form).

What this can't do is deal with any errors from plain SQL statements, but I'm not sure if that's an issue. If it is then those might need to be changed to dynamic SQL inside a PL/SQL block.

like image 32
Alex Poole Avatar answered Oct 26 '22 15:10

Alex Poole