where to see the error message from RAISE_APPLICATION_ERROR? - oracle

I created a trigger in an Oracle database. This trigger will be executed before a insert procedure, to kill all duplicate data. The procedure is executed by a C# application.
TRIGGER Kill_Duplicates
BEGIN
IF ( xxx ) THEN
Raise_application_error(-22222, ' is duplicate!');
END IF;
END
Where to read the message from Raise_application_error? for example, if some duplicates data enter the database, it triggers the Raise_application_error, where to read this - "(-22222, ' is duplicate!')"?
Is there any ways to debug trigger? if my trigger wasn't correct, for example, syntax problem, logic problem, then how to read the exception message of the trigger itself? how would i know and how to get the exceptions/errors?

The exception will be passed to the session that executed the DML statement that caused the trigger to be executed.
I'm suspicious that your error message suggests that you are trying to enforce integrity with a trigger. That's usually a Bad Thing.

Related

Can a trigger in Oracle saves data to log table and raises an exception as well?

guys:
I wonder if there is a way to write a trigger in Oracle to do both things: saving data to a log table and raising a user defined exception as well?
I am trying to figure out a strange error on my team's database, which causes data inconsistency per business logic. Multiple team's application can access this database. So I wrote a trigger to monitor certain column in a table which causes the problem. I want to save data such as user ID, saving time etc. to a log table if value is incorrect, but I also want to raise exception to attract attention. However, whenever my trigger raises the user defined exception, saving data to log table is not finished. Can anyone give a suggestion about it? Thank you in advance.
You can write a logging function that uses an autonomous transaction
create or replace procedure log_autonomous( p_log_message in varchar2,
p_other_parameters... )
as
pragma autonomous_transaction;
begin
insert into log_table ...
commit;
end;
and then call that logging function from your trigger
create or replace trigger my_trigger
before insert or update on some_table
for each row
declare
begin
if( some_bad_thing )
then
log_autonomous( 'Some message', ... );
raise_application_error( -20001, 'Some error' );
end if;
end;
The log_table message will be preserved because it was inserted in a separate (autonomous) transaction. The triggering transaction will be rolled back because the trigger raises an exception.

A SQL exception was caught. The error was: ORA-04098: trigger is invalid and failed re-validation

I have created a trigger with the below code
create or replace trigger DTE_SAVE_ORIGINAL_VAL
after update
on attrvaldesc
FOR Each row
when (new.field2 is null)
Declare
attrvaloriginal attrval.attrval_id%TYPE;
attrval_id attrval.attrval_id%TYPE;
language_id attrvaldesc.language_id%type;
storeent_id attrval.storeent_id%type;
PRAGMA AUTONOMOUS_TRANSACTION;
Begin
Dbms_Output.Put_Line(:OLD.attrval_id);
select attrval_id into attrvaloriginal from attrval where identifier = (select identifier||'_original' from attrval where attrval_id= :OLD.attrval_id and storeent_id=10051) and storeent_id=10051;
if (attrvaloriginal > 0) then
Dbms_Output.Put_Line(attrvaloriginal);
Dbms_Output.Put_Line(:NEW.value);
delete from attrval where attrval_id = attrvaloriginal and storeent_id=10051;
commit;
END IF;
End;
The trigger has compiled and when i trigger a job which updates attrvaldesc table, I'm facing the below exception
Exception message:
A SQL exception was caught. The error was: ORA-04098: trigger 'WCS_ADMIN_HFI.DTE_SAVE_ORIGINAL_VAL' is invalid and failed re-validation
Stack trace:
com.ibm.commerce.foundation.dataload.exception.DataLoadSQLException: A SQL exception was caught. The error was: ORA-04098: trigger 'WCS_ADMIN_HFI.DTE_SAVE_ORIGINAL_VAL' is invalid and failed re-validation
To check if any errors in my trigger I did a
SHOW ERRORS TRIGGER DTE_SAVE_ORIGINAL_VAL;
I returned the below
18/1 PLS-00103: Encountered the symbol "DROP"
The code you've shown doesn't include the word 'drop'. But the error message also refers to line 18. In a trigger a PLS error only refers to the PL/SQL section, starting with declare or begin. Your PL/SQL section only has 16 lines, from declare to end;. This indicates the problem is not quite in what you've shown.
From that we can deduce that you've created your trigger as part of a script, and the next statement was dropping an object:
create or replace trigger DTE_SAVE_ORIGINAL_VAL
...
End;
drop ...
Because it's PL/SQL the trigger creation needs to be submitted with a / character. At the moment everything after your actual trigger, down to the next time a / appears in your script (or the end of the script, potentially), is being accidentally included as part of the trigger definition, which means it's including things that are not valid PL/SQL. From the error that includes a drop, but it may also include other statements, dropping, creating or altering any number of objects.
So you need to add a slash after the trigger in your script:
create or replace trigger DTE_SAVE_ORIGINAL_VAL
...
End;
/
drop ...
You can just re-run the trigger statement on its own, but bear in mind that whatever followed it - everything that was accidentally treated as part of the trigger - was not executed at all, so you may be missing other objects, or have them built differently to how you expect (if the script was supposed to drop and then recreate objects).
You might want to fix and then re-run the whole script, as long as you haven't added any data that would destroy - which is likely if you're now updating data. If that isn't a safe thing to do then see what else wasn't done, and execute those parts manually too, again watching out for potential data loss.

Populating a database in PostgreSQL

The following link on the PostgreSQL documentation manual http://www.postgresql.org/docs/8.3/interactive/populate.html says that to disable autocommit in postgreSQL you can simply place all insert statements within BEGIN; and COMMIT;
However I have difficulty in capturing any exceptions that may happen between the BEGIN; COMMIT; and if an error occurs (like trying to insert a duplicate PK) I have no way to explicitly call the ROLLBACK or COMMIT commands. Although all insert statements are automatically rolled back, PostgreSQL still expects an explicit call to either the COMMIT or ROLLBACK commands before it can consider the transaction to be terminated. Otherwise, the script has to wait for the transaction to time out and any statements executed thereafter will raise an error.
In a stored procedure you can use the EXCEPTION clause to do this but the same does not apply in my circumstance of performing bulk inserts. I have tried it and the exception block did not work for me because the next statement/s executed after the error takes place fails to execute with the error:
ERROR: current transaction is aborted, commands ignored until end of transaction block
The transaction remains open as it has not been explicitly finalised with a call to COMMIT or ROLLBACK;
Here is a sample of the code I used to test this:
BEGIN;
SET search_path TO testing;
INSERT INTO friends (id, name) VALUES (1, 'asd');
INSERT INTO friends (id, name) VALUES (2, 'abcd');
INSERT INTO friends (id, nsame) VALUES (2, 'abcd'); /*note the deliberate mistake in attribute name and also the deliberately repeated pk value number 2*/
EXCEPTION /* this part does not work for me */
WHEN OTHERS THEN
ROLLBACK;
COMMIT;
When using such technique do I really have to guarantee that all statements will succeed? Why is this so? Isn't there a way to trap errors and explicitly call a rollback?
Thank you
if you do it between begin and commit then everything is automatically rolled back in case of an exception.
Excerpt from the url you posted:
"An additional benefit of doing all insertions in one transaction is that if the insertion of one row were to fail then the insertion of all rows inserted up to that point would be rolled back, so you won't be stuck with partially loaded data."
When I initialize databases, i.e. create a series of tables/views/functions/triggers/etc. and/or loading in the initial data, I always use psql and it's Variables to control the flow. I always add:
\set ON_ERROR_STOP
to the top of my scripts, so whenever I hit any exception, psql will abort. It looks like this might help in your case too.
And in cases when I need to do some exception handling, I use anonymous code blocks like this:
DO $$DECLARE _rec record;
BEGIN
FOR _rec IN SELECT * FROM schema WHERE schema_name != 'master' LOOP
EXECUTE 'DROP SCHEMA '||_rec.schema_name||' CASCADE';
END LOOP;
EXCEPTION WHEN others THEN
NULL;
END;$$;
DROP SCHEMA master CASCADE;

How to create error log for stored procedure in oracle 10g?

I need an example of creating error log file for stored procedure in oracle.
please give me an example with table creation and stored procedure creation and error log creation.
Thanks in advance
EDIT (relevant info from other question)
Suppose there is a stored procedure. When I am executing that stored procedure, some expected error/exception may occur, so I need to create an error log table in which all the errors will automatically be store whenever I will execute the stored procedure.
For example, if there is some column which does not allow null values, but the user is entering null values, then that error should be generated and it should stored in the error log table.
You haven't really given a lot of detail about your requirements. Here is a simple error log table and a procedure to log error messages into it:
CREATE TABLE error_log (ts TIMESTAMP NOT NULL, msg VARCHAR2(4000));
CREATE PROCEDURE log_error (msg IN VARCHAR2) IS
BEGIN
INSERT INTO error_log (ts, msg)
VALUES (SYSTIMESTAMP, SUBSTR(insert_log.msg, 1, 4000));
END log_error;
You might or might not need it to be an autonomous transaction. That would depend on whether you want the log to record errors from procedures that rollback their changes.
Typically, this will be implemented in a more generic logging system which would log not only errors, but warnings and debug info too.
If you want a DML statement (insert/update/delete) to log an error for each row (instead of just failing on the first row that errors), you can use the LOG ERRORS clause - instead of the statement failing, the statement will succeed, and the rows that were not inserted/updated/deleted will be written to the error log table you specify, along with the error code and error message applicable. Refer to the link provided by vettipayyan.
If you want all exceptions that are raised within a procedure to be logged, you can catch them with WHEN OTHERS:
BEGIN
-- your code here
EXCEPTION
WHEN OTHERS THEN
log_error(DBMS_UTILITY.format_error_stack);
log_error(DBMS_UTILITY.format_error_backtrace);
RAISE;
END;
Here's the page with code samles:
DML ErrorLogging

Oracle triggers error are not captured while using ADODB

I have and application which uses Adodb to insert data in Oracle table(customers database).
Data is successfully inserted if there are no errors.
If there is any error like invalid datatype etc. Error is raised and captured by my application and dumped in log gile.
My customer has written their own triggers on this particular table. When a record is inserted few other checking are done be fore the data insertion
Now all fine until now.
But recently we found that many a times data is not inserted in the oracle table.
When checked in log file no error was found.
Then I logged the query which was executed.
Copied the query to oracle Sql prompt and executed it gave error of trigger.
My Issue is
Customer is not ready to share the details of trigger.
Error is not raised while inserting to oracle table so we are not able to log it or take any action.
The same qry when executed directly in oracle the trigger errors are show.
Help needed for
Why the error is not raised in ADODB
Do I have to inform customer to implement any error raising
Anything that you can suggest for resolving the issue
I have 0% to 10% knowledge of Oracle
"Copied the query to oracle Sql prompt and executed it gave error of trigger." Since the ADO session doesn't report an error, it may be that the error from the trigger is misleading. It may simply be a check on the lines of "Hey, you are not allowed to insert into this table except though the application".
"Error is not raised while inserting to oracle table so we are not able to log it or take any action."
If the error isn't raised at the time of insert, it MAY be raised at the time of committing. Deferred constraints and materialized views could give this.
Hypothetically, I could reproduce your experience as follows:
1. Create a table tab_a with a deferrable constraint initially deferred (eg val_a > 10)
2. The ADO session inserts a row violating the constraint but it dooesn't error because the constraint is deferred
3. The commit happens and the constraint violation exception fires and the transaction is rolled back instead of being committed.
So see if you are catering for the possibility of an error in the commit.
It may also be something else later in the transaction which results in a rollback of the whole transaction (eg a deadlock). Session tracing would be good. Failing that, look into a SERVERERROR trigger on the user to log the error (eg in a file, so it won't be rolled back)
http://download-west.oracle.com/docs/cd/B19306_01/server.102/b14200/statements_7004.htm#i2153530
You can log your business logic in log table.
But you have to use stored procedure to log the message.
Stored procedure should have pragma Transaction such that your log data must be saved in log table.
You are trigger should have error handling - and in error handling , you have to call Logged stored procedure (which have pragma transaction)
I've never used adodb ( and I assume that is what you are using, not ADO.NET?).. But, a quick look at its references leads to this question.. Are you actually checking the return state of your query?
$ok = $DB->Execute("update atable set aval = 0");
if (!$ok) mylogerr($DB->ErrorMsg());

Resources