I had a number of triggers that used to work in Oracle 8i, that worked to capture both the before, and after values of a row, as well as the sql used to do the update.(I realize there would be cases where this might not be 100% reliable, but it worked very well for our purposes).
These stopped capturing the sql at all when we upgraded to Oracle 11i.
Now they just capture the SQL in the package itself. eg:SELECT USER, SYS_CONTEXT ('USERENV', 'TERMINAL') TERMINAL, SYS_CONTEXT ('USERENV', 'SESSIONID') SESSIONID, (SELECT NVL (MODULE, 'NULL') FROM V$SESSION WHERE AUDSID = SYS_CONTEXT ('USERENV', 'SESSIONID')) PROGRAM, (SELECT MACHINE FROM V$SESSION WHERE AUDSID
We are going to be moving to Oracle 19C (Standard Edition), and I would like to be able to create triggers on various tables to capture the actual sql that changed the values in the records again.
Below is an excerpt from a package I created that was invoked through triggers to capture this information before:
create or replace PACKAGE BODY audit_pkg_gerASPROCEDURE check_val ( l_tname IN VARCHAR2, l_cname IN VARCHAR2, l_new IN VARCHAR2, l_old IN VARCHAR2, l_pkey in VARCHAR2) ISv_user VARCHAR2 (100);v_terminal VARCHAR2 (100);v_sessionid VARCHAR2 (100);v_program VARCHAR2 (200);v_machine VARCHAR2 (200);v_host VARCHAR2 (100);v_os_user VARCHAR2 (100);v_ipadd VARCHAR2 (200);v_sqltext VARCHAR2 (256);BEGINIF ( l_new <> l_old OR (l_new IS NULL AND l_old IS NOT NULL) OR (l_new IS NOT NULL AND l_old IS NULL))THENBEGINSELECT USER, SYS_CONTEXT ('USERENV', 'TERMINAL') terminal,SYS_CONTEXT ('USERENV', 'SESSIONID') sessionid,(SELECT NVL (module, 'NULL')FROM v$sessionWHERE audsid = SYS_CONTEXT ('USERENV', 'SESSIONID'))program,(SELECT machineFROM v$sessionWHERE audsid = SYS_CONTEXT ('USERENV', 'SESSIONID'))machine,SYS_CONTEXT ('USERENV', 'HOST') HOST,SYS_CONTEXT ('USERENV', 'OS_USER') os_user,SYS_CONTEXT ('USERENV', 'IP_ADDRESS') ip_address,(select sql_text from (select max(decode(piece,0,sql_text, null)) || max(decode(piece,1,sql_text, null)) ||max(decode(piece,2,sql_text, null)) || max(decode(piece,3,sql_text, null)) sql_textfrom v$sqltext_with_newlines vt, v$session vswhere vs.sql_address = vt.addressand vs.sql_hash_value = vt.hash_valueand vs.audsid = SYS_CONTEXT ('USERENV', 'SESSIONID')and piece < 4and command_type in (2,3,6,7)group by command_type) where rownum = 1) sql_textINTO v_user, v_terminal,v_sessionid,v_program,v_machine,v_host,v_os_user,v_ipadd,v_sqltextFROM DUAL;INSERT INTO audit_table ( tabnam, colnam, oldval, newval, dbuser, machine, host_path, os_user, ipaddr, program, TIMESTAMP, sqltext, pkey) VALUES ( UPPER (l_tname), UPPER (l_cname), l_old, l_new, v_user, v_machine, v_host, v_os_user, v_ipadd, v_program, SYSDATE, v_sqltext, l_pkey);EXCEPTION WHEN OTHERSTHENNULL;END;END IF;END;
and here would be an example trigger that invoked the package:
create or replace trigger g_aud_bookingafter update or insert or delete on bookingfor each rowbegin declare primary_key varchar2(80) := 'cust=' || :new.customer || ', ' || 'order_no=' || :new.order_no || ', ' || 'order_date=' || TO_CHAR(:new.order_date, 'YYYY-MM-DD'); begin if deleting then primary_key := 'cust=' || :old.customer || ', ' || 'order_no=' || :old.order_no || ', ' || 'order_date=' || TO_CHAR(:old.order_date, 'YYYY-MM-DD'); end if; audit_pkg_ger.check_val('booking', 'CUSTOMER', :new.CUSTOMER, :old.CUSTOMER, primary_key); audit_pkg_ger.check_val('booking', 'ORDER_NO', :new.ORDER_NO, :old.ORDER_NO, primary_key); audit_pkg_ger.check_val('booking', 'ORDER_DATE', :new.ORDER_DATE, :old.ORDER_DATE, primary_key); end;end;
(both the trigger and the package are only partially shown, as the actual details aren't relevant to the issue)
Now, I can capture the before and after values of any column with a similar trigger as this (just not the SQL).
...and I can use Standard Auditing to capture both the SQL, and Bind Variables (but not the before and after values).
Combined, this is all the information I want...
...but I would like these two sets of information to be either captured together, or linked at trigger time so it's easy to view the sql, bind variables, and before and after values of each audited column.
I considered adding rowdependencies
to all our tables to capture the scn
number, so it could possibly be linked to the Oracle Audit logs, but that's just not feasible/practical.
I also considered using Oracle Workspace Manager
, but it comes with far too many restrictions for it to work either.
Any ideas or suggestions appreciated.