有朋友问我,怎样才能制造出数据不一致的效果,比如要达到如下目的:
SQL> select object_name,object_id from testdrop2 where object_id=21886;
OBJECT_NAME OBJECT_ID
-------------------------------------------------------------------------------- ----------
java/util/jar/JarOutputStream 19083
这里明明我where条件中指定的object_id为21886,但是实际上select出来后object_id却变成了19083。
在这篇文章里,我们人为构造了上述不一致的情况,这并没有太大的实际意义,只是这篇文章里提到的方法可以作为解决ORA-08102错误的一种手段。
463479.1里提到:
An ORA-08102 indicates that there is a mismatch between the key(s) stored in the index and the values stored in the table. What typically happens is the index is built and at some future time, some type of corruption occurs, either in the table or index, to cause the mismatch.
好了,我们来看我如何构造上述例子:
SQL> conn dras/astca@astcatest;
Connected to Oracle9i
Connected as dras
SQL> create index idx_testdrop2_objid on testdrop2(object_id) tablespace testtbs3;
Index created
SQL> select object_name,object_id from testdrop2 where object_id=21886;
OBJECT_NAME OBJECT_ID
-------------------------------------------------------------------------------- ----------
sun/io/CharToByteISO8859_4 21886
现在是一切正常的,我们现在要让oracle在执行select object_name,object_id from testdrop2 where object_id=21886的时候返回的查询结果中object_id不等于21886。
SQL> select dump(21886,16) from dual;
DUMP(21886,16)
-----------------------
Typ=2 Len=4: c3,3,13,57
SQL> select HEADER_FILE,HEADER_BLOCK from dba_segments where segment_name='IDX_TESTDROP2_OBJID';
HEADER_FILE HEADER_BLOCK
----------- ------------
137 652
我们现在dump 137-653至137-781(alter system dump datafile 137 block min 653 block max 781),从产生的trace文件里去查找字符串 C3 03 13 57,可以查到如下内容:
buffer tsn: 88 rdba: 0x224002bd (137/701)
scn: 0x0008.a
frmt: 0x02 chkval: 0xd013 type: 0x06=trans data
Block header dump: 0x224002bd
Object id on Block? Y
seg/obj: 0x1507e csc: 0x08.a
brn: 0 bdba: 0x22400289 ver: 0x01
inc: 0 exflg: 0
......中间内容省略
row#58[7206] flag: -----, lock: 0
col 0; len 4; (4): c3 03 13 57
col 1; len 6; (6): 22 40 00 8d 00 00
好了,现在我们来将c3 03 13 57所对应的rowid由22 40 00 8d 00 00改为22 40 00 8f 00 00。
SQL> select EXTENT_MANAGEMENT,SEGMENT_SPACE_MANAGEMENT from dba_tablespaces where tablespace_name='TESTTBS3';
EXTENT_MANAGEMENT SEGMENT_SPACE_MANAGEMENT
----------------- ------------------------
LOCAL AUTO
从上面可以看到,c3 03 13 57所在的行的offset是7206,这是一个相对地址,需要加上一个BASE,BASE的计算方法为:
对于ASSM:76+(itc-1)*24
对于MSSM:68+(itc-1)*24
所以我们这里实际用到的offset为7206+76+(2-1)*24=7306
shutdown上述数据库,然后用BBED将22 40 00 8d 00 00改为22 40 00
$ bbed parfile=par.bbd
Password:
BBED: Release
Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.
************* !!! For Oracle Internal Use only !!! ***************
BBED> set file 137
FILE# 137
BBED> set block 701
BLOCK# 701
BBED> set offset 7306
OFFSET 7306
BBED> dump
File: /dras20/astca/testtbs3_01.dbf (137)
Block: 701 Offsets: 7306 to 7817 Dba:0x224002bd
------------------------------------------------------------------------
03135506
00390000
01310002
03134506
012d
03133506
<32 bytes per line>
BBED> modify /x
Warning: contents of previous BIFILE will be lost. Proceed? (Y/N) y
File: /dras20/astca/testtbs3_01.dbf (137)
Block: 701 Offsets: 7306 to 7817 Dba:0x224002bd
------------------------------------------------------------------------
03135506
00390000
01310002
03134506
012d
03133506
<32 bytes per line>
BBED> sum apply
Check value for File 137, Block 701:
current = 0xd011, required = 0xd011
好了,现在我们已经改完了,最后我们来看一下改过之后的效果:
startup上述数据库,并执行select object_name,object_id from testdrop2 where object_id=21886;
SQL> conn dras/astca@astcatest;
Connected to Oracle9i
Connected as dras
SQL> select object_name,object_id from testdrop2 where object_id=21886;
OBJECT_NAME OBJECT_ID
-------------------------------------------------------------------------------- ----------
java/util/jar/JarOutputStream 19083
可以看到,我们的目的已经实现了。
顶,bbed 相当熟练啊~~~