Monitoring Streams Replication| How to Display Detailed Information About Apply Errors?
SQL scripts below can display detailed information about error transactions in the error queue in a database.
These scripts are designed to display information about LCRs, but you can extend them to display information about any non-LCR messages used.
To use these scripts, complete the following steps:
Step 1) Grant Explicit SELECT Privilege on the DBA_APPLY_ERROR View
Step 2) Create a Procedure that Prints the Value in an ANYDATA Object
Step 3) Create a Procedure that Prints a Specified LCR
Step 4) Create a Procedure that Prints All the LCRs in the Error Queue
Step 5) Create a Procedure that Prints All the Error LCRs for a Transaction
Step 1 Grant Explicit SELECT Privilege on the DBA_APPLY_ERROR View
The user who creates and runs the print_errors and print_transaction procedures described in the following sections must be granted explicit SELECT privilege on the DBA_APPLY_ERROR data dictionary view. This privilege cannot be granted through a role. Running the GRANT_ADMIN_PRIVILEGE procedure in the DBMS_STREAMS_AUTH package on a user grants this privilege to the user. To grant this privilege to a user directly, complete the following steps:
GRANT SELECT ON DBA_APPLY_ERROR TO strmadmin; GRANT EXECUTE ON DBMS_APPLY_ADM TO strmadmin; |
Step 2 Create a Procedure that Prints the Value in an ANYDATA Object
The following procedure prints the value in a specified ANYDATA object for some selected data types. Optionally, you can add more data types to this procedure.
CREATE OR REPLACE PROCEDURE print_any(data IN ANYDATA) IS tn VARCHAR2(61); str VARCHAR2(4000); CHR VARCHAR2(1000); num NUMBER; dat DATE; rw RAW(4000); res NUMBER; BEGIN IF data IS NULL THEN DBMS_OUTPUT.PUT_LINE('NULL value'); RETURN; END IF; tn := data.GETTYPENAME(); IF tn = 'SYS.VARCHAR2' THEN res := data.GETVARCHAR2(str); DBMS_OUTPUT.PUT_LINE(SUBSTR(str,0,253)); ELSIF tn = 'SYS.CHAR' THEN res := data.GETCHAR(CHR); DBMS_OUTPUT.PUT_LINE(SUBSTR(CHR,0,253)); ELSIF tn = 'SYS.VARCHAR' THEN res := data.GETVARCHAR(CHR); DBMS_OUTPUT.PUT_LINE(CHR); ELSIF tn = 'SYS.NUMBER' THEN res := data.GETNUMBER(num); DBMS_OUTPUT.PUT_LINE(num); ELSIF tn = 'SYS.DATE' THEN res := data.GETDATE(dat); DBMS_OUTPUT.PUT_LINE(dat); ELSIF tn = 'SYS.RAW' THEN -- res := data.GETRAW(rw); -- DBMS_OUTPUT.PUT_LINE(SUBSTR(DBMS_LOB.SUBSTR(rw),0,253)); DBMS_OUTPUT.PUT_LINE('BLOB Value'); ELSIF tn = 'SYS.BLOB' THEN DBMS_OUTPUT.PUT_LINE('BLOB Found'); ELSE DBMS_OUTPUT.PUT_LINE('typename is ' || tn); END IF; END print_any; / |
Step 3 Create a Procedure that Prints a Specified LCR
The following procedure prints a specified LCR. It calls the print_any procedure created in “Create a Procedure that Prints the Value in an ANYDATA Object”.
CREATE OR REPLACE PROCEDURE print_lcr(lcr IN ANYDATA) IS typenm VARCHAR2(61); ddllcr SYS.LCR$_DDL_RECORD; proclcr SYS.LCR$_PROCEDURE_RECORD; rowlcr SYS.LCR$_ROW_RECORD; res NUMBER; newlist SYS.LCR$_ROW_LIST; oldlist SYS.LCR$_ROW_LIST; ddl_text CLOB; ext_attr ANYDATA; BEGIN typenm := lcr.GETTYPENAME(); DBMS_OUTPUT.PUT_LINE('type name: ' || typenm); IF (typenm = 'SYS.LCR$_DDL_RECORD') THEN res := lcr.GETOBJECT(ddllcr); DBMS_OUTPUT.PUT_LINE('source database: ' || ddllcr.GET_SOURCE_DATABASE_NAME); DBMS_OUTPUT.PUT_LINE('owner: ' || ddllcr.GET_OBJECT_OWNER); DBMS_OUTPUT.PUT_LINE('object: ' || ddllcr.GET_OBJECT_NAME); DBMS_OUTPUT.PUT_LINE('is tag null: ' || ddllcr.IS_NULL_TAG); DBMS_LOB.CREATETEMPORARY(ddl_text, TRUE); ddllcr.GET_DDL_TEXT(ddl_text); DBMS_OUTPUT.PUT_LINE('ddl: ' || ddl_text); -- Print extra attributes in DDL LCR ext_attr := ddllcr.GET_EXTRA_ATTRIBUTE('serial#'); IF (ext_attr IS NOT NULL) THEN DBMS_OUTPUT.PUT_LINE('serial#: ' || ext_attr.ACCESSNUMBER()); END IF; ext_attr := ddllcr.GET_EXTRA_ATTRIBUTE('session#'); IF (ext_attr IS NOT NULL) THEN DBMS_OUTPUT.PUT_LINE('session#: ' || ext_attr.ACCESSNUMBER()); END IF; ext_attr := ddllcr.GET_EXTRA_ATTRIBUTE('thread#'); IF (ext_attr IS NOT NULL) THEN DBMS_OUTPUT.PUT_LINE('thread#: ' || ext_attr.ACCESSNUMBER()); END IF; ext_attr := ddllcr.GET_EXTRA_ATTRIBUTE('tx_name'); IF (ext_attr IS NOT NULL) THEN DBMS_OUTPUT.PUT_LINE('transaction name: ' || ext_attr.ACCESSVARCHAR2()); END IF; ext_attr := ddllcr.GET_EXTRA_ATTRIBUTE('username'); IF (ext_attr IS NOT NULL) THEN DBMS_OUTPUT.PUT_LINE('username: ' || ext_attr.ACCESSVARCHAR2()); END IF; DBMS_LOB.FREETEMPORARY(ddl_text); ELSIF (typenm = 'SYS.LCR$_ROW_RECORD') THEN res := lcr.GETOBJECT(rowlcr); DBMS_OUTPUT.PUT_LINE('source database: ' || rowlcr.GET_SOURCE_DATABASE_NAME); DBMS_OUTPUT.PUT_LINE('owner: ' || rowlcr.GET_OBJECT_OWNER); DBMS_OUTPUT.PUT_LINE('object: ' || rowlcr.GET_OBJECT_NAME); DBMS_OUTPUT.PUT_LINE('is tag null: ' || rowlcr.IS_NULL_TAG); DBMS_OUTPUT.PUT_LINE('command_type: ' || rowlcr.GET_COMMAND_TYPE); oldlist := rowlcr.GET_VALUES('old'); FOR i IN 1..oldlist.COUNT LOOP IF oldlist(i) IS NOT NULL THEN DBMS_OUTPUT.PUT_LINE('old(' || i || '): ' || oldlist(i).column_name); print_any(oldlist(i).data); END IF; END LOOP; newlist := rowlcr.GET_VALUES('new', 'n'); FOR i IN 1..newlist.COUNT LOOP IF newlist(i) IS NOT NULL THEN DBMS_OUTPUT.PUT_LINE('new(' || i || '): ' || newlist(i).column_name); print_any(newlist(i).data); END IF; END LOOP; -- Print extra attributes in row LCR ext_attr := rowlcr.GET_EXTRA_ATTRIBUTE('row_id'); IF (ext_attr IS NOT NULL) THEN DBMS_OUTPUT.PUT_LINE('row_id: ' || ext_attr.ACCESSUROWID()); END IF; ext_attr := rowlcr.GET_EXTRA_ATTRIBUTE('serial#'); IF (ext_attr IS NOT NULL) THEN DBMS_OUTPUT.PUT_LINE('serial#: ' || ext_attr.ACCESSNUMBER()); END IF; ext_attr := rowlcr.GET_EXTRA_ATTRIBUTE('session#'); IF (ext_attr IS NOT NULL) THEN DBMS_OUTPUT.PUT_LINE('session#: ' || ext_attr.ACCESSNUMBER()); END IF; ext_attr := rowlcr.GET_EXTRA_ATTRIBUTE('thread#'); IF (ext_attr IS NOT NULL) THEN DBMS_OUTPUT.PUT_LINE('thread#: ' || ext_attr.ACCESSNUMBER()); END IF; ext_attr := rowlcr.GET_EXTRA_ATTRIBUTE('tx_name'); IF (ext_attr IS NOT NULL) THEN DBMS_OUTPUT.PUT_LINE('transaction name: ' || ext_attr.ACCESSVARCHAR2()); END IF; ext_attr := rowlcr.GET_EXTRA_ATTRIBUTE('username'); IF (ext_attr IS NOT NULL) THEN DBMS_OUTPUT.PUT_LINE('username: ' || ext_attr.ACCESSVARCHAR2()); END IF; ELSE DBMS_OUTPUT.PUT_LINE('Non-LCR Message with type ' || typenm); END IF; END print_lcr; / |
Step 4 Create a Procedure that Prints All the LCRs in the Error Queue
The following procedure prints all of the LCRs in all of the error queues. It calls the print_lcr procedure created in ” Step3) Create a Procedure that Prints a Specified LCR”.
CREATE OR REPLACE PROCEDURE print_errors IS CURSOR c IS SELECT LOCAL_TRANSACTION_ID, SOURCE_DATABASE, MESSAGE_NUMBER, MESSAGE_COUNT, ERROR_NUMBER, ERROR_MESSAGE FROM DBA_APPLY_ERROR ORDER BY SOURCE_DATABASE, SOURCE_COMMIT_SCN; i NUMBER; txnid VARCHAR2(30); source VARCHAR2(128); msgno NUMBER; msgcnt NUMBER; errnum NUMBER := 0; errno NUMBER; errmsg VARCHAR2(2000); lcr ANYDATA; r NUMBER; BEGIN FOR r IN c LOOP errnum := errnum + 1; msgcnt := r.MESSAGE_COUNT; txnid := r.LOCAL_TRANSACTION_ID; source := r.SOURCE_DATABASE; msgno := r.MESSAGE_NUMBER; errno := r.ERROR_NUMBER; errmsg := r.ERROR_MESSAGE; DBMS_OUTPUT.PUT_LINE('*************************************************'); DBMS_OUTPUT.PUT_LINE('----- ERROR #' || errnum); DBMS_OUTPUT.PUT_LINE('----- Local Transaction ID: ' || txnid); DBMS_OUTPUT.PUT_LINE('----- Source Database: ' || source); DBMS_OUTPUT.PUT_LINE('----Error in Message: '|| msgno); DBMS_OUTPUT.PUT_LINE('----Error Number: '||errno); DBMS_OUTPUT.PUT_LINE('----Message Text: '||errmsg); FOR i IN 1..msgcnt LOOP DBMS_OUTPUT.PUT_LINE('--message: ' || i); lcr := DBMS_APPLY_ADM.GET_ERROR_MESSAGE(i, txnid); print_lcr(lcr); END LOOP; END LOOP; END print_errors; / |
To run this procedure after you create it, enter the following:
SET SERVEROUTPUT ON SIZE 1000000
EXEC print_errors
Step 5 Create a Procedure that Prints All the Error LCRs for a Transaction
The following procedure prints all the LCRs in the error queue for a particular transaction. It calls the print_lcr procedure created in “Create a Procedure that Prints a Specified LCR”.
CREATE OR REPLACE PROCEDURE print_transaction(ltxnid IN VARCHAR2) IS i NUMBER; txnid VARCHAR2(30); source VARCHAR2(128); msgno NUMBER; msgcnt NUMBER; errno NUMBER; errmsg VARCHAR2(2000); lcr ANYDATA; BEGIN SELECT LOCAL_TRANSACTION_ID, SOURCE_DATABASE, MESSAGE_NUMBER, MESSAGE_COUNT, ERROR_NUMBER, ERROR_MESSAGE INTO txnid, source, msgno, msgcnt, errno, errmsg FROM DBA_APPLY_ERROR WHERE LOCAL_TRANSACTION_ID = ltxnid; DBMS_OUTPUT.PUT_LINE('----- Local Transaction ID: ' || txnid); DBMS_OUTPUT.PUT_LINE('----- Source Database: ' || source); DBMS_OUTPUT.PUT_LINE('----Error in Message: '|| msgno); DBMS_OUTPUT.PUT_LINE('----Error Number: '||errno); DBMS_OUTPUT.PUT_LINE('----Message Text: '||errmsg); FOR i IN 1..msgcnt LOOP DBMS_OUTPUT.PUT_LINE('--message: ' || i); lcr := DBMS_APPLY_ADM.GET_ERROR_MESSAGE(i, txnid); -- gets the LCR print_lcr(lcr); END LOOP; END print_transaction; / |
To run this procedure after you create it, pass to it the local transaction identifier of a error transaction. For example, if the local transaction identifier is 1.17.2485, then enter the following:
SET SERVEROUTPUT ON SIZE 1000000 EXEC print_transaction('1.17.2485') |
How to locate local transaction identifier of a error transaction? To check for apply errors, run the following query:
COLUMN APPLY_NAME HEADING 'Apply|Process|Name' FORMAT A10 COLUMN SOURCE_DATABASE HEADING 'Source|Database' FORMAT A10 COLUMN LOCAL_TRANSACTION_ID HEADING 'Local|Transaction|ID' FORMAT A11 COLUMN ERROR_NUMBER HEADING 'Error Number' FORMAT 99999999 COLUMN ERROR_MESSAGE HEADING 'Error Message' FORMAT A20 COLUMN MESSAGE_COUNT HEADING 'Messages in|Error|Transaction' FORMAT 99999999 SELECT APPLY_NAME, SOURCE_DATABASE, LOCAL_TRANSACTION_ID, ERROR_NUMBER, ERROR_MESSAGE, MESSAGE_COUNT FROM DBA_APPLY_ERROR; |
If there are any apply errors, then your output looks similar to the following:
Apply Local Messages in Process Source Transaction Error Name Database ID Error Number Error Message Transaction ---------- ---------- ----------- ------------ -------------------- ----------- APPLY_FROM MULT3.EXAM 1.62.948 1403 ORA-01403: no data found 1_MULT3PLE.COM APPLY_FROM MULT2.EXAM 1.54.948 1403 ORA-01403: no data found 1_MULT2PLE.COM
Leave a Reply
You must be logged in to post a comment.
[...] Monitoring Streams Replication| How to Display Detailed Information About Apply Errors? [...]