Calling Oracle autonomous stored procedure from trigger - oracle

I have an Oracle trigger which is calling a stored procedure that has PRAGMA AUTONOMOUS_TRANSACTION defined. The values that are passed from the trigger have been committed already but it appears that the values are not available in the stored procedure? I'm not positive of this since the ability to debug/log/commit is difficult and the timing of the output is confusing me a bit. I'd like to know if it's expected that any passed values are simply available in the stored procedure regardless of the AUTONOMOUS_TRANSACTION?
Thanks

Values passed in to a stored procedure as parameters will always be available to the stored procedure. It doesn't matter whether the procedure is declared using an autonomous transaction.
Code running in an autonomous transaction cannot see changes made by the calling transaction. 9 times out of 10, when people are describing problems seeing the data they expect, this is the source of the problem.
If your stored procedure is doing anything other than writing something to a log table, I would be exceptionally cautious about using autonomous transactions. If you are using autonomous transactions for anything other than logging, you are almost certainly using them incorrectly. And you are probably introducing a whole host of bugs related to race conditions and transactional integrity.

"The trigger logic is conditionally
updating Table B which calls the
stored procedure to select from the
values on Table A so that Table B can
be updated with a calculated value. "
Perhaps Table B really ought to be a Materialized View derived from Table A? We can build a lot of complexity into the WHERE clauses of the queries which populate MViews. Find out more.

If you have a row level trigger on table_x, then that trigger can be fired multiple times by the same statement as different rows are impacted by that statement.
The order in which those rows are impacted is indeterminate. As such, the state of table_x is indeterminate during the execution of a row level trigger. This is why the MUTATING TABLE exception is raised.
An autonomous transaction 'cheats' by looking at the committed state of the table (ie excluding all changes made by that statement, and other statements in the transaction).
If you want a stored procedure to look at the state of table_x in response to activity on that table, then it needs to be done after all the rows changes have been made (ie in a statement level trigger, not a row level trigger).
The design pattern for this is often to set a flag (package level variable) in a row level trigger, check the flag in an AFTER statement level trigger, and if necessary action it and reset it.

Related

Handling data in global temporary tables in case of transaction rollback

I've a job which runs with multiple instances i.e. the code base for all instances is same, but each instance works on set of data allocated to it so as to achieve parallelism and better throughput for the application.
These jobs use global temporary table for working through the data as there are multiple complex operations performed before final output is computed.
In case of failure, the transaction is rolled back (as it should), but with this I'm also losing the data in gtt.
Is there a way that the records in gtt can be copied over to another permanent table while rolling back the transaction.
I know it sounds weird, but this is a practical problem I'm facing.
I need to somehow store data in session table in case of failure of any sql, while rolling back the transaction as one of the sql has failed.
Thanks.
Hm, maybe something like this:
create a permanent table which will hold GTT data in case of failure
create an autonomous transaction procedure which would insert into permanent select * from gtt and commit
in exception handler section call that procedure and then rollback
The only way is printing the required data before your rollback.
You can use UTL_FILE to store data in the file. Later, you can use external table concept of oracle to retrieve data in the table.
Cheers!!

Statement-level trigger in Oracle

I can't fully understand how a statement-level trigger works. It executes once for each transaction right? If I have this AFTER INSERT trigger and what it does inside is that it updates one specific column if it meets the condition (ex for column status, UPDATE table_name SET STATUS = "Single" WHERE COLUMN is null).
Are the newly inserted data only the ones get to be affected? Or every data in the table that has this null value in column status. I'll be glad hearing your knowledge about this.
A statement level trigger will fire once after the triggering statement has run, unlike a row level trigger which fires for each affected row.
After statement triggers are generally used to do processing of the set of data - e.g. logging into a table, or running some post-statement processing (usually a procedure).
If you're wanting to update a value in every affected row, then I would advise using a before row level trigger. The update statement in your question would affect all rows where the COLUMN column is null.
Whether a trigger is actually the right thing to use is debatable. However, I would recommend you look at the documentation and also this Oracle-base article to gain a better understanding of how triggers work and when you might use them.

Dynamically read the columns of the :NEW object in an oracle trigger

I have an oracle trigger that needs to copy values from the updated table to another table.
The problem is that the columns aren't known when the trigger is created. Part of this system allows the table schema to be updated by the application. (don't ask).
Essentially what I want to do is pivot the table to another table.
I have a stored procedure that will do the pivot, but I can't call it as part of the trigger because it does a select on the table being updated. Causing a "mutating" error.
What would be ideal would be to create a dynamic scripts that reads all the column names from user_tab_cols for the updated table, and reads the value from the :new object.
But of course...I can't :)
:NEW doesn't exist at the point the dynamic script is executed. So something like the following would fail:
EXECUTE IMMEDIATE `insert into pivotTable values(:NEW.' || variableWithColumnName ||')';
So, I'm stuck.
I can't read from the table that was updated, and I can't read the value that was updated from the :NEW object.
Is there anyway to accomplish this other than rebuilding the trigger each time the schema is changed?
No. You'll need to rebuild the trigger whenever the table changes.
If you want to get really involved, you could write a procedure that dynamically generated the DDL to CREATE OR REPLACE the trigger by reading user_tab_columns. You could then create a DDL trigger that fired when the table was altered, submitted a job via dbms_job that called the procedure to recreate the trigger. That works but it's a rather large number of moving parts which means that it can fail in all sorts of subtle and spectacular ways particularly if the application that is making schema changes on the fly decides to add columns in the middle of the day.

Modification of Trigger in Oracle Database

If a trigger is already in function what will be the effect if i will replace a small part of it ,so many records are getting inserted in table A continuously in which the trigger is applied.
Trigger X is running in table A,
total records are getting insterted per minute are 1000
If i have replaced the trigger what will be the Impact of It for those service who are accesing the table.
Thanks in advance
A CREATE TRIGGER DDL should have no impact on your running DML transactions. Exclusive locks are not required on the table in order to add the trigger.
A CREATE OR REPLACE DDL is slightly different. It has to change an existing object. If the trigger is actively firing, the new trigger will try to lock the trigger object in the library cache before altering it. No impact on the table.
I generally observe that triggers execute immediately.
If you have tested your trigger, you should have no issues. If the trigger is correct, it will go into effect, and the impact shall be according to the logic that you've written in the trigger. The act of creating the trigger is not of concern, but the correctness of the trigger code is. So test it well.
Any transactions underway at the time you create the trigger will finish without firing the trigger.
Any future transactions will fire the trigger.

How to call the Triggers in user deefined way?

I created the Employee table which contains EmpNo,EName,EDesignation as its fields.Also i created the 3 Triggers namely Trigger_1,Trigger_2 and Trigger_3.All the Triggers are Statement level triggers and fired after the update done in the table.Now i want the following orders in which the triggers are going to fired when the update statement is executed.
The Order is
Trigger_3,
Trigger_1,
Trigger_2
Can anyone tell me the way to fire the trigger events in userdefined way?I m using Oracle 9i
Trigger Evaluation Order
Quote from Oracle documentation:
Although any trigger can run a
sequence of operations either in-line
or by calling procedures, using
multiple triggers of the same type
enhances database administration by
permitting the modular installation of
applications that have triggers on the
same tables.
Oracle Database executes all triggers
of the same type before executing
triggers of a different type. If you
have multiple triggers of the same
type on a single table, then Oracle
Database chooses an arbitrary order to
execute these triggers.
Each subsequent trigger sees the
changes made by the previously fired
triggers. Each trigger can see the old
and new values. The old values are the
original values, and the new values
are the current values, as set by the
most recently fired UPDATE or INSERT
trigger.
To ensure that multiple triggered
actions occur in a specific order, you
must consolidate these actions into a
single trigger (for example, by having
the trigger call a series of
procedures).
see also http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14251/adfns_triggers.htm
Have one trigger with the contents of the three.
If you cannot, for reasons for modularization, reusability..., create three stored procedures and call these one by one in the single trigger.
Upgrade to 11g and you can define trigger execution order

Resources