I'm having a hard time figuring out how to handle exceptions in PL/SQL when the error is returned by a parallel query server.
Consider the following :
BEGIN
EXECUTE IMMEDIATE('ALTER <SOME_INDEX> REBUILD PARALLEL(4) );
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE = -01652 THEN
DBMS_OUTPUT.PUT_LINE('Not enought space');
ELSE
DBMS_OUTPUT.PUT_LINE('[SQLCODE] -> '||SQLERRM);
NULL;
END IF;
END;
I'm trying to handle ORA-01652 to notify that the tablespace is full.
The problem here is that I don't catch :
ORA-01652 unable to extend temp segment by 128 in tablespace <TBS>
but rather :
ORA-12801: error signaled in parallel query server P001
So ORA-01652 isn't stored in SQLCODE. How could I handle the real exception here?
Thanks a lot.
Trap the error (a rare case in which WHEN OTHERS is required) and use DBMS_Utility.Format_Error_Stack to read the underlying error.
http://docs.oracle.com/cd/B28359_01/appdev.111/b28419/d_util.htm#sthref9680
Alright, problem solved using David Aldridge's pieces of advice. If someone's having a similar problem, here's the solution I came up with, using the INSTR function :
BEGIN
EXECUTE IMMEDIATE('ALTER <SOME_INDEX> REBUILD PARALLEL (DEGREE 4));
EXCEPTION
WHEN OTHERS THEN
-- If the error_stack contains the error code, then the error obviously occured
-- INSTR will return the position of the string we are looking for
-- otherwise, it will just return 0, hence the search condition :
IF INSTR(DBMS_UTILITY.FORMAT_ERROR_STACK,'ORA-01658') > 0 THEN
DBMS_OUTPUT.PUT_LINE('Tablespace full, too bad!');
ELSE
DBMS_OUTPUT.PUT_LINE('ERROR : '||DBMS_UTILITY.FORMAT_ERROR_STACK);
END IF;
END;
Related
I am seeing a weird issue while executing an SQL stored procedure. Below is the format of the stored proc:
CREATE PROC abc
(
#status int=0 output
)
AS
BEGIN TRY
--Does some transactions
END TRY
BEGIN CATCH
SET #status=-1
END CATCH
return #status
I understand I should have added/logged more details like Error Number, Error Message etc in my catch block but I didnt realize such an issue would occur. Currently, the stored procedure in production sometimes returns a -1 status. The strange part is all the transactions in the try block have been successfully committed. I dont understand then why is the procedure getting into the catch block. I tried to manually execute the procedure with same data it completes successfully and returns status=0. I added extra logging in test environment and tested more than 300 times, but was not able to reproduce the issue. In production I am not allowed to make any changes. Hence, I asked our DBA's to enable trace logging, but that didnt help us much in getting any exception details.
I would really appreciate if there is any way I can troubleshoot this issue. Also are there any options for the DBA's to monitor this procedure and capture the exception
i had reviewed plsql code written by somebody else , i figured out he use return commands in exception block, i already read in java programming this is not good practice, i also check some exception example of plsql and see that return is not used , so does anybody could confirm this is invalid?
EXCEPTION WHEN OTHERS THEN
create_log ( p_caller_user, 'E', '4', NULL
, 'INTEREST_CALCULATION_TOOLS', 'CALCULATE_INTEREST'
, V_SPY_COUNTER
, 'UNEXPECTED ERROR DURING FUNCTION EXECUTION, ACC NO : '
|| ',' || SQLERRM()
|| p_account_id, SQLCODE(), SYSDATE);
RETURN -2;
Your example is out of context so it's impossible to say if there is some problems or not. The code snippet is probably reporting the error condition correctly in the context (by create_log-procedure) even it is this case in others exception handler (that might be a sign of problems and according to Tom Kyte it's for sure).
In general I see no issues returning from PL/SQL function non-others exception handler.
Oracle PL/SQL documentation says nothing about the subject:
Subprogram Parts
RETURN Statement
Continuing Execution After Handling Exceptions
I use the following pattern routinely to return default values when optional value is not found:
create or replace function f1 return dual.dummy%type is
v_dummy dual.dummy%type;
begin
select dummy into v_dummy from dual where dummy = 'Y';
return v_dummy;
exception
when no_data_found then
return 'Z';
end;
/
(Note that I only process well known error cases where I know how the situation should be handled.)
I find the alternative way unnecessary verbose, though it will please return-once purists:
create or replace function f2 return dual.dummy%type is
v_dummy dual.dummy%type;
begin
begin
select dummy into v_dummy from dual where dummy = 'Y';
exception
when no_data_found then
v_dummy := 'Z';
end;
return v_dummy;
end;
/
Compiling the functions with all warnings turned on return only the following non-related warnings:
Warning: PLW-06015: parameter PLSQL_DEBUG is deprecated; use PLSQL_OPTIMIZE_LEVEL = 1
Warning(1,1): PLW-05018: unit F1 omitted optional AUTHID clause; default value DEFINER used
Although it may not give any error it is not at all a good coding practice to do so...
Please refer http://docs.oracle.com/cd/B10500_01/appdev.920/a96624/08_subs.htm
It clearly specifies "The executable part contains statements, which are placed between the keywords BEGIN and EXCEPTION (or END). One or more RETURN statements must appear in the executable part of a function. The exception-handling part contains exception handlers, which are placed between the keywords EXCEPTION and END."
So here even though it doesn't give any problems for now, you shouldn't do this.. I hope this helps.
I use this code in my stored procedure to get info on a SQLEXCEPTION:
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
GET DIAGNOSTICS condition 1
#SQLState = RETURNED_SQLSTATE, #SQLMessage = MESSAGE_TEXT;
SELECT CONCAT('Database error occurred, state - ',#SQLState, '; error msg - ', #SQLMessage) INTO #errorString;
CALL Collectors_Errors
(#errorString,
'Collectors_UpdateGame',
barcodeApp,
usernameApp);
END;
The problem with this code is even though I know what the error is, it doesn't tell me at which line it occurred. And some of my sprocs are very long.
Is there a way to determine which line number, or what the line was, that caused the exception?
You can try the rdebug tool for debugging your stored procedures. I have not used it, but I find the rest of the tools in common_schema to be super helpful.
There may be an easier quick fix for finding exactly where this one error comes from, but in you are working with long stored procedures you may find rdebug to be helpful beyond this one error.
I am trying to port an Oracle trigger to MySQL. There's an EXCEPTION WHEN OTHERS statement in the trigger and while I have found equivalent statements for everything else, I cannot find one for this. The trigger is something like:
IF (yada yada)
THEN
BEGIN
SELECT a
INTO generic_variable1
FROM table
WHERE condition;
SET generic_variable2 = value1;
EXCEPTION WHEN OTHERS --this part needs to be replaced by valid MySQL syntax
SET generic_variable2 = value2;
END;
END IF;
How do I convert that part into MySQL?
You should understand that MySQL has a very limited stored proc / trigger language compared to Oracle. While porting to MySQL, many Oracle users say over and over again, "I can't believe MySQL can't do X!!!!"
The closest thing to EXCEPTION WHEN OTHERS may be DECLARE CONTINUE HANDLER.
Example (not tested):
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET #generic_variable2 = 1;
But you'd declare that before the block of code that might throw the exception, not after.
See http://dev.mysql.com/doc/refman/5.5/en/declare-handler.html for full docs.
I'm hoping this isn't just duplicating this question.
I have read the documentation but I don't think I fully understand how to use this properly yet.
I would like to catch errors thrown in my stored procedures and log those errors in a table. This is mostly for experimental purposes. I am wondering is there a way to catch any error and then log the code and error to a table.
So far it looks like I have to declare a different handler for each error. Is this correct or is there a way to catch all errors and get the code and message.
For example in each stored procedure I'm declaring a couple of handlers
DECLARE EXIT HANDLER FOR 1062
BEGIN
SELECT 'Attempt to create a duplicate entry occurred';
END;
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
SELECT 'Unexpected Error Ocurred';
END;
Instead of
SELECT 'custom message';
I want to do
INSERT INTO errorLogs(code, message);
Is this possible without declaring a load of handlers and adding each code manually?
Really appreciate any help pointing me in the right direction.
It looks like this is not really possible until I can use an updated version of MYSQL with DIAGNOSTICS. I found this question which is basically the same as mine. Ah well.