views:

93

answers:

3

Is it possible to see the DML (SQL Statement) that is being run that caused a trigger to be executed?

For example, inside an INSERT trigger I would like to get this:

"insert into myTable (name) values ('Fred')"

I read about ora_sql_txt(sql_text) in articles such as this but couldn't get it working - not sure if that is even leading me down the right path?

We are using Oracle 10.

Thank you in advance.

=========================

[EDITED] MORE DETAIL: We have the need to replicate an existing database (DB1) into a classified database (DB2) that is not accessible via the network. I need to keep these databases in sync. This is a one-way sync from (DB1) to (DB2), since (DB2) will contain additional tables and data that is not contained in the (DB1) system.

I have to determine a way to sync these databases without bringing them down (say, for a backup and restore) because it needs to stay live. So I thought that if I can store the actual DML being run (when data changes), I could "play-back" the DML on the new database to update it, just like someone was hand-entering it back in.

I can't bring over all the data because of the sheer size of it, and I can't just copy over the changed records because of FK constraints and the order in which I insert/update records. I figured that if I could "play-back" a log of what happened, using the exact SQL that changed the master, I could keep the databases in sync.

My current plan of attack was to keep a log of all records that were changed, inserted, and deleted and when I want to sync, the system generates DML to insert/update/delete those records. Then I just take the .SQL file to the classified system and run the script. The problem I'm running into are FKs. (Because when I generate the DML I only know what the current state of the data is, not it's path to get there - so ordering of statements is an issue). I guess I could disable all FK's, do the merge, then re-enable all FK's...

So - does my approach of storing the actual DML as-it-happens suck pondwater, or is there a better solution???

A: 

That function only works for 'event' triggers as discussed here. You should look into Fine-Grained Auditing as a mechanism for this. Details here

Gary
Thanks Gary - maybe the auditing is where I want to go, but I've been told I don't want to keep that on in production systems. I'm going to add a comment under my question that explains in a bit more detail what I'm trying to accomplish.
BigWorld
In that case, you are not just capturing the SQL, but the bind variables and possibly session state as well. Go with Shannon's suggestion and look into either Materialized Views, Oracle Replication (eg Streams, GoldenGate) or a third party replication solution. Don't try to build your own.
Gary
Thanks Gary - I'm currently reading deeper into Oracle replication. Maybe there is something I missed, but I'm a SQL Server DBA so most of this is greek to me. Do any of those replication solutions (that you know of) offer an option to generate some kind of delta file for servers not on the network?Thanks!
BigWorld
I think that fits in more with GoldenGate, but I don't think it will be cheap. I'd recommend another question on replication, but that may fit more on ServerFault as the 'admin' site.
Gary
BigWorld
+1  A: 

When the trigger code runs don't you already know the dml that caused it to run?

    CREATE OR REPLACE TRIGGER Print_salary_changes
      BEFORE INSERT OR UPDATE ON Emp_tab
      FOR EACH ROW
      ...

In this case it must have been an insert or an update statement on the emp_tab table.

To find out if it was an update or an insert

if inserting then
...
elsif updating then
...
end if;

The exact column values are available in the :old and :new pseudo-columns.

Rene
Actually, I don't know what statement caused it to fire off - which is what I'm trying to get my grubby little fingers on. I know I can see what fields changed (as your example showed above) but I want to know *if* I cound access the exact SQL statement being run that caused that trigger to fire. I'll add a comment under my question that explains in a bit more detail what I'm trying to accomplish, but I didn't want to get too detailed if there was an easy way. Thanks Rene!
BigWorld
Also, you are correct - I *could* generate the appropriate SQL using :old/:new pseudo-columns knowing if it was an insert/update but based on the sheer # of tables and columns, and the amount of code I'd have to write and maintain, I figured I'd just try to grab the actual SQL, since it's already been done for me. ;)
BigWorld
+1  A: 

"does my approach of storing the actual DML as-it-happens suck pondwater?" Yes..

  1. Strict ordering of the DML on your DB1 does not really exist. Multiple processes, muiltiple cores, things essentially happening at the essentially the same time.

  2. And the DML, even when it happens sequentially doesn't act like it. Say the following two update statements run in seperate processes with seperate transactions, where the update in transaction 2 starts before transaction 1 commits:

     update table_a set col_a = 10 where col_b = 'A' -- transaction 1
     update table_a set col_c = 'Error' where col_a = 10 -- transaction 2
    

Since the changes made in the first transaction are not visibible to the second transaction, the rows changed by the second transaction will not include those of the first. But if you manage to capture the DML and replay it sequentially, transaction 1's changes will be visible, so transaction 2's changes will be different. (See pages 40 and 41 of Tom Kyte's Expert Oracle Database Architecture Second Edition.)

  1. Hopefully you are using bind variables, so the DML by itself wouldn't be meaningful: update table_a set col_a = :col_a where id = :id Now what? Ok, so you want the DML with it's variable bindings.

  2. Do you use sequences? If so, the next_val will not stay in synch between DB1 and DB2. (For example, instance failures can cause lost values, are both systems going to fail at the same time?) And if you are dealing with RAC, where the next_val varies depending on node, forget it.

I would start by investigating Oracle's replication.

Shannon Severance
BigWorld
The target DB is not "read-only" if you are applying DML to it. By that I mean, if you run DML that includes things like `insert ... values (sequence_X.nextval` your insert will get the value of `sequence_x.nextval` that is applicable on the target, which may be different then the source.Sorry, but I don't have any experience with replication, I just know it's there, thus "I would start by investigating ...". In addition to streams replication there is advanced replication.The Target DB includes data besides the tables you want to replicate?
Shannon Severance
Correct, which is why I double-quoted "read-only" :) - it's read-only to the *user*. In other words, no new data will be generated on that server. And since I'm inserting the primary key that was generated on the master server, a sequence will never be used on the target. (Truth be told, the read-only instance doesn't even have the sequences created). Thanks for all your comments Shannon - I learned a few things along the way, and will be closing this question today.
BigWorld
Sorry I missed the last part of your question: "The Target DB includes data besides the tables you want to replicate?" --- Yes, the target contains additional tables that are not contained in the source DB.
BigWorld