ORA-00600: Internal message code, arguments: [01578] [...] [...] [] [] []. ORA-01578: Oracle data block corrupted (file ..., block ...).This message tells you that somewhere in your database, a block of data has been corrupted (at the byte level) in such a way that Oracle7 causes the internal exception to be raised each time a SQL statement accesses (reads or writes) that block. This article describes the options available to you for solving the ORA-00600[01578] error. As you'll see, in most cases the problem is easy to solve, although some cases require more effort and time.
select ds.* from dba_segments ds, sys.uet$ e where ds.header_file=e.segfile# and ds.header_block=e.segblock# and e.header_file=If the segment turns out to be an index segment, you can solve the problem very quickly. Because all the table data required for re-creating the index is still accessible, you can drop and re-create the index (the block will be reformatted when it's taken from the free-space list and reused for the index).and between e.block# and e.block#+e.length-1;
If the segment turns out to be a table segment, you have several options for solving the problem:
This option involves a lot of effort: shutting down the
database, restoring an old enough datafile, and then recovering that datafile
by applying multiple archived log files and restarting the database. It
will, however, restore your corrupted table segment completely up to the
time you discovered the corrupted data block.
select /*+index(X X_I) */ a, b, c from X;The execution plan for this query is:
Select statement >table access (by rowid) X >index range scan X_IYou must now exclude the corrupted block from being accessed, to avoid the internal exception ORA-00600[01578]. Because the block and file numbers are substrings of the rowid, doing this is easy:
select /*+index(X X_I) */ a, b, c from X where rowid not like(A rowid holds the physical address of a row. Its value is formatted as follows: xxxxxxxx.yyyy.zzz. The first part, x, equals the block offset within the datafile. The second part, y, equals the row offset within the data block. The last part, z, identifies the datafile. All values are in hexadecimal representation.)||'.%.'|| ;
The execution plan for this query stays the same:
Select statement >table access (by rowid) X >index range scan X_IBut it is important to realize that the WHERE clause gets evaluated right after the index is accessed and before the table is accessed. Otherwise, you'll still get the ORA-00600[01578] exception.
Using the above query as a subquery in an insert statement, you can restore all rows of still valid blocks to a new table.
Since the index holds the actual column values of the indexed columns, you can also use the index to restore all indexed columns of rows that reside in the corrupted block. The following query retrieves only indexed columns a and b from rows inside the corrupted block:
select /*+index(X X_I) */ a, b from X where rowid likeThe optimizer will not access the table segment for this query. It can retrieve the column values using the index segment only. The execution plan for the above query is:||'.%.'|| ;
Select statement >index range scan X_IUsing this technique, you can restore all of the indexed-column values of the rows inside the corrupted block, without having to access the corrupted block at all. Suppose that column c of table X was also indexed by index X_I2. This enables you to completely restore rows inside the corrupted block.
First, restore columns a and b by using index X_I:
create table X_a_b(rowkey,a,b) as select /*+index(X X_I) */ rowid, a, b from X where rowid likeThen restore column c, using index X_I2:||'.%.'|| ;
create table X_c(rowkey,c) as select /*+index(X X_I2) */ rowid, c from X where rowid likeAnd finally, join the columns together, using the restored rowid:||'.%.'|| ;
select x1.a, x1.b, x2.c from X_a_b x1, X_c x2 where x1.rowkey=x2.rowkey;In summary, you can use indexes on the corrupted table segment to restore all columns of all rows that are stored outside the corrupted data blocks. Of rows inside the corrupted data blocks, you can restore only the columns that were indexed. You might even be able to use an old version of the table (via Import) to further restore nonindexed columns of these records.
declare v_rowid varchar2(18); v_xrec X%rowtype; e_invalid_rowid exception; pragma exception_init(e_invalid_rowid,-1410); begin for v_uetrec in (select file# file, block# start_block, block#+length#-1 end_block from sys.uet$ where segfile#=6 and segblock#=64) --- Identifies our segment X. loop for v_blk in v_uetrec.start_block..v_uetrec.end_block loop if v_uetrec.file<>6 and v_blk<>886 --- 886 in file 6 is our corrupted block. then for v_row in 0..200 --- 200 is maximum number of rows per block for segment X. loop begin select a,b,c into v_rec from x where rowid=chartorowid('0000'||hex(v_blk)||'.'|| hex(v_row)||'.'||hex(v_uetrec.file); insert into x_saved(a,b,c)values (v_rec.a,v_rec.b,v_rec.c); commit; exception when e_invalid_rowid then null; end; end loop; /*row-loop*/ end if; end loop; /*blk-loop*/ end loop; /*uet-loop*/ end; /This code assumes that block IDs never exceed four hexadecimal places.
create or replace function hex(v_num in binary_integer) return varchar2 as --- Assumption: 'v_num' is less than power(16,4). v_tmp3 binary_integer; v_tmp2 binary_integer; v_tmp1 binary_integer; v_tmp0 binary_integer; v_buf binary_integer; function hexchr(v_c in binary_integer) return varchar2 as begin if v_c between 0 and 9 then return to_char(v_c); elsif v_c=10 then return 'A'; elsif v_c=11 then return 'B'; elsif v_c=12 then return 'C'; elsif v_c=13 then return 'D'; elsif v_c=14 then return 'E'; elsif v_c=15 then return 'F'; end if; end; function div(i in binary_integer, j in binary_integer) return binary_integer as v_buf binary_integer:=i; a binary_integer:=0; begin while v_buf>=j loop a:=a+1; v_buf:=v_buf-j; end loop; return a; end; begin v_buf:=v_num; v_tmp3:=div(v_buf,4096); v_buf:=v_buf-4096*v_tmp3; v_tmp2:=div(v_buf,256); v_buf:=v_buf-256*v_tmp2; v_tmp1:=div(v_buf,16); v_buf:=v_buf-16*v_tmp1; v_tmp0:=v_buf; return hexchr(v_tmp3)||hexchr(v_tmp2)||hexchr(v_tmp1) ||hexchr(v_tmp0); end; /
Exit to : Oracle
Hints and Tips