I am actually calling an SQL script from Unix using the below code. The SQL script has millions of DML's which will be run on my database. The requirement is that if an DML fails then the script should abort with an exit code rather than skipping to the next DML. Currently,it is executing all the DML's without breaking at the DML that failed. We actually need more control on the script. How can we achieve this? Plz help.
SCRIPT BODY
#! /bin/sh
echo "Script started at `date`"
#************** Execute the extract sql on Staging database***************#
`sqlplus -s $CCBSTGID/$CCBSTGPASSWRD#$CCBSTGDBASE <<EOF
whenever sqlerror exit 2;
whenever error exit 3;
set termout on
set echo on
set serveroutput on
set pagesize 0
set linesize 500
set heading off
set verify on
set feedback on
spool output1.txt;
#DMLFile.sql
spool off;
quit;
EOF`
RC=$?
echo $RC
if [ ${RC} != 0 ]
then
echo "Script execution failed"
exit 1
fi
The problem is that you aren't wrapping the DML statements within PL/SQL blocks so the WHENEVER SQLERROR ... isn't working like you expect. Here is a test case demonstrating the issue.
-- File: dmlfile.sql
update a set name = 'A';
foo; -- erroneous command to cause error
update a set name = 'B';
Before...
C:\>perl wrapper.pl
1 row updated.
SP2-0042: unknown command "foo" - rest of line ignored.
1 row updated.
Oops, both updates statements executed; script did not exit after error.
After wrapping with BEGIN and END
-- File: dmlfile.sql
begin
update a set name = 'A';
foo; -- erroneous command to cause error
update a set name = 'B';
end;
/
Running it:
C:\>perl wrapper.pl
foo; -- erroneous command to cause error
*
ERROR at line 3:
ORA-06550: line 3, column 2:
PLS-00201: identifier 'FOO' must be declared
ORA-06550: line 3, column 2:
PL/SQL: Statement ignored
Also, I don't know of any command WHENEVER ERROR, perhaps you were thinking WHENEVER OSERROR ?
See previous answer: PL/SQL: is there an instruction to completely stop the script execution?
Try wrapping all of your DML in a BEGIN ... END block:
-- DMLFile.sql
BEGIN
-- your DML statements here
END;
/
or wrap each individual logical block of statements in a block.
-- DMLFile.sql
WHENEVER SQLERROR EXIT SQL.SQLCODE ROLLBACK;
BEGIN
-- block 1
END;
/
BEGIN
-- block 2
END;
/
WHENEVER SQLERROR EXIT is a SQLPlus directive, not standard SQL, but is fairly portable; it works in SQLPlus, SQL Developer, Toad, PL/SQL Developer, SQLsmith and others.
An alternative would be to use some other GUI client around your DML or pass the whole script to a tool that can do batch mode. Toad will stop after one error and prompt you.
SQLPLUS couldn't parse the command so it never made it to SQL. The SP2-0042 error is a sqlplus error, so it doesn't get caught by the WHENEVER SQLERROR EXIT directive. Sadly, There's no equivalent SQLPLUSERROR directive....
However, starting in the 11g sqlplus (not the database), Oracle has provided a error logging facility that can be used to trap various errors.
SQLPLUS> set errorlogging on
I finally found the reference here: SQLPlus User Guide
Related
I'm trying to execute a script on SQL PLus, it's simple.
SET serveroutput ON;
DECLARE
mode NUMBER(1) := 1;
IF (mode = 1) THEN
prompt 'HERE'
END IF;
prompt 'fim'
I call the script from SQLPlus using sqlplus user/pw#db and #myscript.sql after a successful connection. But the output is strange for me:
Conectado a:
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options
SQL> #myscript.sql
9
10
11
And it continues to print this sequence indefinitely.
What am I doing wrong?
From your edited question... you have to terminate the PL/SQL block with a / on a new line to make it end and run, otherwise SQL*Plus will keep prompting for more lines of code (which is the numbers you're seeing). The documentation shows how to run PL/SQL blocks. And prompt is a SQL*Plus command so you can't use it inside a PL/SQL block. You also don't have your block syntax right:
SET serveroutput ON;
DECLARE
mode NUMBER(1) := 1;
BEGIN
IF mode = 1 THEN
DBMS_OUTPUT.PUT_LINE('HERE');
END IF;
END;
/
prompt fim
You cannot use sqlplus command in plsql.We can use dbms_output instead which will display the output in SQL prompt
SET serveroutput ON;
DECLARE
mode NUMBER(1) := 1;
BEGIN
IF (mode = 1) THEN
dbms_output.put_line('HERE');
END IF;
dbms_output.put_line('fim');
END;
/
Go to your oracle home Oracle\product\<version>\client_2\sqlplus\admin\glogin.sql and add the following lines to enable printing globally,
SET ECHO ON;
SET TERM ON;
WHENEVER SQLERROR EXIT FAILURE ROLLBACK;
SET DEFINE OFF;
i got a little problem in Oracle. I try to create a sequence for generating IDs in a table that already has data in it. I try to use the following anonymous block.
declare y varchar2(2000);
BEGIN
SELECT 'CREATE SEQUENCE ID_SEQ MINVALUE 1 MAXVALUE 9999999999 START WITH ' || (max(ID)+1) || ' INCREMENT BY 1 CACHE 20;' INTO y FROM TEST_TABLE;
--dbms_output.put_line(y);
execute immediate y;
end;
I get the following error:
Error report:
ORA-00911: invalid character
ORA-06512: at line 5
00911. 00000 - "invalid character"
If I execute the value of the y variable it works perfectly. I'm using SQL Developer as input interface and working on a 11g r2 Oracle server. I found similar codes where 'INCREMENT BY' parameter were script generated. Can someone explain my error?
When you execute immediate, the command you run should not have a semi-colon on the end; that is a command separator in SQL Developer (and SQL*Plus, and other clients), not part of the SQL statement itself.
SELECT 'CREATE SEQUENCE ID_SEQ MINVALUE 1 MAXVALUE 9999999999 START WITH '
|| (max(ID)+1) || ' INCREMENT BY 1 CACHE 20' INTO y FROM TEST_TABLE;
This is shown in the examples for plain SQL. Just to help confuse you though, if you are using PL/SQL within the dynamic SQL, you do still need semi-colons appropriate to PL/SQL itself - though not the executing / you'd use to run it directly from a client. This is shown in other examples.
Problem
I just want to see the value of a variable. I don't understand why this has to be so difficult.
My SQL Statement
--set serveroutput on format wrapped; Tried this too
SET SERVEROUTPUT ON;
--DBMS_OUTPUT.ENABLE(32000); Tried with, and without this
vend_num xx.VENDOR_CWT.VEND_NO%TYPE;
SELECT vend_no
INTO vend_num
FROM xx.VENDOR_NAME
WHERE VENDOR_NAME1 = 'xxxx';
dbms_output.put_line(vend_num);
The Error I'm Geting
Error starting at line 13 in command:
dbms_output.put_line(vend_num)
Error report:
Unknown Command
What I've Tried
I've tried the following answers:
Print text in Oracle SQL Developer SQL Worksheet window
Printing the value of a variable in SQL Developer
I've done what this answer suggested with the gui: https://stackoverflow.com/a/7889380/496680
I've tried exec dbms_output[...] as some posts have suggested.
Question
How do I just print the value of vend_num;
DBMS_Output is a PL/SQL package, so you'd call it from within PL/SQL code.
declare
end_num xx.VENDOR_CWT.VEND_NO%TYPE;
begin
SELECT vend_no
INTO vend_num
FROM xx.VENDOR_NAME
WHERE VENDOR_NAME1 = 'xxxx';
dbms_output.put_line(vend_num);
end;
/
Need a way to redirect PL/SQL program error message to a log file when executing it in sqlplus.
Say the PL/SQL program is named send_2012.sql and it has the following exception block
EXCEPTION
WHEN NO_DATA_FOUND
THEN
var_err := 'Data not found. ';
WHEN OTHERS
THEN
var_err := 'Error in '
|| $$plsql_unit
|| ' | '
|| SQLERRM
|| ' | '
|| 'Details: '
|| DBMS_UTILITY.format_error_backtrace;
END;
To run the PL/SQL program in a KornShell (ksh) script, I have:
sqlplus some_username/'some_password' #some_database \
#/some/directory/send_2012.sql \
$parameter1 $paramenter2
Suppose error occurs when executing send_2012.sql, how can I redirect the error message from var_err to /some/log/directory/log_send_2012.txt?
Much appreciated.
Setup your script like this:
-- test.sql script run from sqlplus
set serveroutput on
set echo on
WHENEVER SQLERROR EXIT SQL.SQLCODE
spool on
spool test.log
declare
l_val date;
begin
select sysdate into l_val from dual where 1=0;
exception
when others then raise;
end;
/
spool off
log into sqlplus from that directory and run:
SQL>#test.sql
You'll find the exceptions in the log file (test.log).
I worked around the logging issue, here is what I did:
Within the pl/sql program I inserted DBMS_PUTLINE("error messages goes here, etc"); to both the program body and exception sections.
When calling sqlplus from a Korn shell script, I used a regular output redirect to log pl/sql exceptions:
sqlplus some_username/'some_password' #some_database \
#/some/directory/send_2012.sql \
$parameter1 $paramenter2 \
> /some/log/directory/send_2012.log
What I did may not be the best solution. Wrap Spool before and after your pl/sql program may give you more options on formatting, but it may also include the output result (say from the select statement) when system executes the program successfully.
Is there a way that you can have SERVEROUTPUT set to ON in sqlplus but somehow repress the message "PL/SQL procedure successfully completed" that is automatically generated upon completed execution of a plsql procedure?
Use the command:
SET FEEDBACK OFF
before running the procedure. And afterwards you can turn it back on again:
SET FEEDBACK ON
This has worked well for me in sqlplus, but I did just notice that "set feedback off" suppresses errors in Sql Developer (at least version 17.2.0.188). Just something to be aware of if you use Sql Developer:
create or replace procedure test_throw_an_error as buzz number; begin dbms_output.put_line('In test_throw_an_error. Now, to infinity!'); buzz:=1/0; end;
/
set serveroutput on
set feedback off
exec test_throw_an_error;
exec dbms_output.put_line('Done, with feedback off');
set feedback on
exec test_throw_an_error;
exec dbms_output.put_line('Done, with feedback on');
Result:
Procedure TEST_THROW_AN_ERROR compiled
In test_throw_an_error. Now, to infinity!
Done, with feedback off
In test_throw_an_error. Now, to infinity!
Error starting at line : 11 in command -
BEGIN test_throw_an_error; END;
Error report -
ORA-01476: divisor is equal to zero
ORA-06512: at "ECTRUNK.TEST_THROW_AN_ERROR", line 1
ORA-06512: at line 1
01476. 00000 - "divisor is equal to zero"
*Cause:
*Action:
Done, with feedback on
PL/SQL procedure successfully completed.