There is a document that answers the question if any tag was set without clarifying what tag was set specifically:
Using Logminer to Identify if a Non-NULL Tag Has Been Set Using DBMS_STREAMS.SET_TAG (Doc ID 740574.1)
Besides, LogDump can be used to display the tag information when GoldenGate is in use: GGSTOKEN.
My experiments revealed that the required information can be obtained using X$LOGMNR_CONTENTS.DUMP_INFO as the example below demonstrates.
SYS@PDB> grant create session, create table, select_catalog_role to tc identified by tc; Grant succeeded. SYS@PDB> SYS@PDB> grant execute on dbms_streams_adm to tc; Grant succeeded. SYS@PDB> SYS@PDB> alter user tc quota 100m on users; User altered. SYS@PDB> SYS@PDB> conn tc/tc@pdb Connected. TC@PDB> TC@PDB> TC@PDB> select current_scn from v$database; CURRENT_SCN ----------- 2221571 TC@PDB> TC@PDB> create table t(id int, s varchar2(30)) 2 segment creation immediate; Table created. TC@PDB> TC@PDB> exec dbms_streams_adm.set_tag(hextoraw('112233')) PL/SQL procedure successfully completed. TC@PDB> TC@PDB> insert into t values (1, 'tag_1'); 1 row created. TC@PDB> select dbms_transaction.local_transaction_id from dual; LOCAL_TRANSACTION_ID -------------------------------------------------------------------------------- 3.29.732 TC@PDB> commit; Commit complete. TC@PDB> TC@PDB> exec dbms_streams_adm.set_tag(hextoraw('deadbeef')) PL/SQL procedure successfully completed. TC@PDB> TC@PDB> insert into t values (11, 'tag_1'); 1 row created. TC@PDB> insert into t values (12, 'tag_1'); 1 row created. TC@PDB> select dbms_transaction.local_transaction_id from dual; LOCAL_TRANSACTION_ID -------------------------------------------------------------------------------- 8.26.689 TC@PDB> commit; Commit complete. TC@PDB> TC@PDB> select current_scn from v$database; CURRENT_SCN ----------- 2221592Here is summary information for the transactions above:
TRANSACTION | TAG |
---|---|
3.29.732 | 112233 |
8.26.689 | DEADBEEF |
The following query shows only the redo opcode 5.20 (Transaction Audit) rows for these transactions:
SQL> col log_file old_v log_file SQL> SQL> select member log_file 2 from v$log l, 3 v$logfile f 4 where l.status = 'CURRENT' 5 and f.group# = l.group#; LOG_FILE -------------------------------------------------------------------------------- /opt/oracle/oradata/ORCLCDB/redo02.log SQL> SQL> exec dbms_logmnr.add_logfile('&log_file.') PL/SQL procedure successfully completed. SQL> SQL> exec dbms_logmnr.start_logmnr(options => dbms_logmnr.dict_from_online_catalog) PL/SQL procedure successfully completed. SQL> select xidusn, xidslt, xidsqn, 2 dump_info 3 from x$logmnr_contents 4 where (xidusn, xidslt, xidsqn) in ((3,29,732),(8,26,689)) 5 and scn between 2221571 and 2221592 6 and component_id = 5 7 and opcode = 20; XIDUSN XIDSLT XIDSQN DUMP_INFO ---------- ---------- ---------- ---------------------------------------------------------------------------------------------------- 3 29 732 CHANGE #3 MEDIA RECOVERY MARKER CON_ID:3 SCN:0x0000000000000000 SEQ:0 OP:5.20 ENC:0 FLG:0x0000 session number = 264 serial number = 29041 transaction name = version 318767104 audit sessionid 24 Client Id = login username = TC REPL MARKER: 06 00 09 00 00 00 01 00 03 11 22 33 XIDUSN XIDSLT XIDSQN DUMP_INFO ---------- ---------- ---------- ---------------------------------------------------------------------------------------------------- 8 26 689 CHANGE #3 MEDIA RECOVERY MARKER CON_ID:3 SCN:0x0000000000000000 SEQ:0 OP:5.20 ENC:0 FLG:0x0000 session number = 264 serial number = 29041 transaction name = version 318767104 audit sessionid 24 Client Id = login username = TC REPL MARKER: 06 00 0a 00 00 00 01 00 04 de ad be efIt appears that the 9th byte of a REPL MARKER value stores the length of the tag. Therefore, it is possible to extract a tag using the following query:
SQL> select xidusn, xidslt, xidsqn, repl_marker, 2 utl_raw.substr(repl_marker, 10, to_number(utl_raw.substr(repl_marker, 9, 1), 'xxxxxxxxxx')) tag, 3 dump_info 4 from ( 5 select xidusn, xidslt, xidsqn, 6 hextoraw(replace(regexp_substr(dump_info, 'REPL MARKER:.(.*).', 1, 1, 'n', 1), ' ')) repl_marker, 7 dump_info 8 from x$logmnr_contents 9 where (xidusn, xidslt, xidsqn) in ((3,29,732),(8,26,689)) 10 and scn between 2221571 and 2221592 11 and component_id = 5 12 and opcode = 20); XIDUSN XIDSLT XIDSQN REPL_MARKER TAG DUMP_INFO ---------- ---------- ---------- -------------------------- ---------- ---------------------------------------------------------------------------------------------------- 3 29 732 060009000000010003112233 112233 CHANGE #3 MEDIA RECOVERY MARKER CON_ID:3 SCN:0x0000000000000000 SEQ:0 OP:5.20 ENC:0 FLG:0x0000 session number = 264 serial number = 29041 transaction name = version 318767104 audit sessionid 24 Client Id = login username = TC REPL MARKER: 06 00 09 00 00 00 01 00 03 11 22 33 XIDUSN XIDSLT XIDSQN REPL_MARKER TAG DUMP_INFO ---------- ---------- ---------- -------------------------- ---------- ---------------------------------------------------------------------------------------------------- 8 26 689 06000A000000010004DEADBEEF DEADBEEF CHANGE #3 MEDIA RECOVERY MARKER CON_ID:3 SCN:0x0000000000000000 SEQ:0 OP:5.20 ENC:0 FLG:0x0000 session number = 264 serial number = 29041 transaction name = version 318767104 audit sessionid 24 Client Id = login username = TC REPL MARKER: 06 00 0a 00 00 00 01 00 04 de ad be efIt is quite handy that X$LOGMNR_CONTENTS.DUMP_INFO contains the same or, at least, the subset of the information present in the redo log dump, that allows to use it for sophisticated analysis in SQL*Plus without resorting to low-level dumps or the LogDump utility of Oracle GoldenGate.
I was using a vanilla 19.3 database on Linux for these experiments.
Комментариев нет:
Отправить комментарий
Примечание. Отправлять комментарии могут только участники этого блога.