First Impression on BBED: modify table data

BBED功能相当强大,因为可以用来修改block上的内容,因此很显然可以通过BBED来修改表上的数据,直接绕过通过SQL语句对表的操作。

本文尝试通过BBED来修改表中的一条记录。

建立实验环境

首先建立实验环境,建立一张表test, 插入一条记录 (1, 'Frank'), 如下...

SQL> create user frank identified by frank;

User created.

SQL
> grant resource, connect to frank;

Grant succeeded.

SQL
> conn frank/frank
Connected.
SQL
> create table test(id integer, name varchar2(10));

Table created.

SQL
> insert into test values(1, 'Frank');

1 row created.

SQL
> commit;

Commit complete.

SQL
> select * from test;

ID NAME
---------- ----------
1 Frank

SQL
> select rowid, dbms_rowid.rowid_block_number(rowid), dbms_rowid.rowid_relative_fno(rowid)
2 from test;

ROWID DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)
------------------ ------------------------------------
DBMS_ROWID.ROWID_RELATIVE_FNO(ROWID)
------------------------------------
AAAM8RAAEAAAAGUAAA 404
4


SQL
> alter system dump file 4 block 404;
alter system dump file 4 block 404
*
ERROR at line
1:
ORA
-01961: Invalid dump option


SQL
> alter system dump datafile 4 block 404;
alter system dump datafile 4 block 404
*
ERROR at line
1:
ORA
-01031: insufficient privileges


SQL
> conn / as sysdba
Connected.
SQL
> grant alter system to frank;

Grant succeeded.

SQL
> conn frank/frank
Connected.
SQL
> alter system dump datafile 4 block 404;

System altered.


通过上面的操作,确定了我们刚才在表test中插入的一条记录位于4号数据文件上第404个block上面。

 

设置BBED

现在把BBED 的dba 设置成 4, 404

[oracle@ora10g ~]$ bbed
Password:

BBED: Release
2.0.0.0.0 - Limited Production on Thu Feb 17 20:33:45 2011

Copyright (c)
1982, 2005, Oracle. All rights reserved.

************* !!! For Oracle Internal Use only !!! ***************

BBED
> set dba 4, 404
BBED
-00312: no LISTFILE specified


BBED
> set listfile='/u01/app/oracle/temp/listdatafile.log'
BBED
-00202: invalid parameter (=)


BBED
> set listfile '/u01/app/oracle/temp/listdatafile.log'
LISTFILE
/u01/app/oracle/temp/listdatafile.log

BBED
> set dba 4, 404
DBA
0x01000194 (16777620 4,404)

可以通过BBED来查看我们刚才在表TEST中插入的记录,如下,(kbdr中这个数组大小为1,表示只有一条记录)

BBED> p kdbr
sb2 kdbr[
0] @118 8076

BBED
> p *kdbr[0]
rowdata[
0]
----------
ub1 rowdata[
0] @8176 0x2c

BBED> x /r
rowdata[
0] @8176
----------
flag
@8176: 0x2c (KDRHFL, KDRHFF, KDRHFH)
lock
@8177: 0x01
cols
@8178: 2

col
0[2] @8179: 0xc1 0x02
col
1[5] @8182: 0x46 0x72 0x61 0x6e 0x6b


BBED
> x /rnc
rowdata[
0] @8176
----------
flag
@8176: 0x2c (KDRHFL, KDRHFF, KDRHFH)
lock
@8177: 0x01
cols
@8178: 2

col
0[2] @8179: 1
col
1[5] @8182: Frank

注意这里面用到的e(x)amine命令, 参数/r表示显示oracle表中每一行记录, /nc表示第一列为数字类型(1),第二列为字符串类型('Frank')。 从上面的输出可以看出,表中有一行记录(1, 'Frank').  同时注意到每一行的开始有3个字节的overhead, 分别表示flag, lock, column count, 因此虽然表中第一行数据从offset 8176开始,实际的数据是从offset 8179开始。而且每个column的数据前面是有至少一个字节是用来存储改column占用的字节数,所以虽然'Frank'这个column是从offset 8182开始,实际存储的字符串'Frank'是从offset 8183开始的。

 

修改数据

现在尝试把表中的'Frank'改成'Fraud'.

首先需要确定'Frank'这个字符串在block中的位置(offset) , 通过find命令来找到大概的位置,然后通过dump命令来进一步确认 (其实从上面的examine命令输出已经可以判断出来Frank这个字符串是从offset 8183开始的),

BBED> find /c Frank
File:
/u01/app/oracle/oradata/orcl/users01.dbf (4)
Block:
404 Offsets: 8183 to 8191 Dba:0x01000194
------------------------------------------------------------------------
4672616e 6b030645 1e

<
32 bytes per line>

BBED
> dump /v dba 4, 404 offset 8183 count 64
File:
/u01/app/oracle/oradata/orcl/users01.dbf (4)
Block:
404 Offsets: 8183 to 8191 Dba:0x01000194
-------------------------------------------------------
4672616e 6b030645 1e l Frank..E.

<
16 bytes per line>

可以确定下来Frank是从offset 8183开始的。那么下面可以通过modify命令来进行数据的修改,将'Frank'修改为'Fraud'...

BBED> modify /c Fraud dba 4, 404 offset 8183
BBED
-00215: editing not allowed in BROWSE mode


BBED
> set mode edit
MODE Edit

BBED
> modify /c Fraud dba 4, 404 offset 8183
File:
/u01/app/oracle/oradata/orcl/users01.dbf (4)
Block:
404 Offsets: 8183 to 8191 Dba:0x01000194
------------------------------------------------------------------------
46726175 64030645 1e

<
32 bytes per line>

BBED
> dump /v dba 4, 404 offset 8183
File:
/u01/app/oracle/oradata/orcl/users01.dbf (4)
Block:
404 Offsets: 8183 to 8191 Dba:0x01000194
-------------------------------------------------------
46726175 64030645 1e l Fraud..E.

<
16 bytes per line>

通过dump命令可以看出block的内容却是被修改成了Fraud了。那么现在通过sql*plus来查看数据是不是改变了...

SQL> select * from test;

ID NAME
---------- ----------
1 Frank

SQL
> alter system flush buffer cache;
alter system flush buffer cache
*
ERROR at line
1:
ORA
-02000: missing SHARED_POOL/BUFFER_CACHE/GLOBAL CONTEXT keyword


SQL
> alter system flush buffer_cache;

System altered.

SQL
> select * from test;
select * from test
*
ERROR at line
1:
ORA
-01578: ORACLE data block corrupted (file # 4, block # 404)
ORA
-01110: data file 4: '/u01/app/oracle/oradata/orcl/users01.dbf'

在查询表之前,通过alter system flush buffer_cache来清空内存中的数据缓存,第一次得到的数据有可能是内存中的。flush之后再重新查询,发现报了一个错误,说block被破坏了!这是因为通过BBED修改了之后没有进行block checksum的重新计算,造成block表现为corrupted.

可以通过sum命令来更新block的checksum,

BBED> sum dba 4, 404
Check value
for File 4, Block 404:
current
= 0x61de, required = 0x6ec5

BBED
> sum dba 4, 404 apply
Check value
for File 4, Block 404:
current
= 0x6ec5, required = 0x6ec5

现在再通过sql*plus来查看一下,

SQL> select * from test;
select * from test
*
ERROR at line
1:
ORA
-01578: ORACLE data block corrupted (file # 4, block # 404)
ORA
-01110: data file 4: '/u01/app/oracle/oradata/orcl/users01.dbf'


SQL
> alter system flush buffer_cache;

System altered.

SQL
> select * from test;

ID NAME
---------- ----------
1 Fraud

现在看到表TEST的内容被改成了Fraud. 需要注意的是,访问表之前,还需要执行下alter system flush buffer_cache命令。

数据块的恢复(revert)

可以通过revert命令来撤销刚才对数据库块的修改,使之回退到BBED启动时候的那个状态。注意,用UNDO命令会失败,因为已经进行过了block的checksum重计算了。操作如下,

BBED> undo
BBED
> modify /x 4672616E6B filename '/u01/app/oracle/oradata/orcl/users01.dbf' block 404. offset 8183.
BBED
-00209: invalid number (4672616E6B)



BBED
> revert dba 4, 404
All changes made to this block will be rolled back. Proceed
? (Y/N) Y
Reverted file '
/u01/app/oracle/oradata/orcl/users01.dbf', block 404

现在通过sql*plus查询确认下...

SQL> alter system flush buffer_cache;

System altered.

SQL
> select * from test;

ID NAME
---------- ----------
1 Frank

可以看到Name又从'Fraud'变成了'Frank'了。

再来一次

现在尝试往表TEST再插入一条记录(2, 'HelloFrank'),

SQL> insert into test values(2, 'HelloFrank');

1 row created.

SQL
> commit;

Commit complete.

SQL
> select * from test;

ID NAME
---------- ----------
1 Frank
2 HelloFrank

SQL
> alter system flush buffer_cache;

System altered.

SQL
> select * from test;

ID NAME
---------- ----------
1 Frank
2 HelloFrank

现在再通过print命令来查看kdbr,发现现在有两条记录了,而且第一条记录的offset还是8176,这个是显然的,因为数据是从block尾部往上插入的,第一条数据位于block的底部,offset并不会因为新数据的插入而改变。

BBED> set dba 4, 404
DBA
0x01000194 (16777620 4,404)

BBED
> p kdbr
sb2 kdbr[
0] @118 8076
sb2 kdbr[
1] @120 8059

BBED
> p kdbr[0]
sb2 kdbr[
0] @118 8076

BBED
> p *kdbr[0]
rowdata[
17]
-----------
ub1 rowdata[
17] @8176 0x2c

BBED
> p /c offset 8176
rowdata[
17]
-----------
ub1 rowdata[
17] @8176 ,

BBED
> dump /v dba 4, 404 offset 8176
File:
/u01/app/oracle/oradata/orcl/users01.dbf (4)
Block:
404 Offsets: 8176 to 8191 Dba:0x01000194
-------------------------------------------------------
2c010202 c1020546 72616e6b 0206ec28 l ,...�..Frank..

<
16 bytes per line>

BBED
>

新插入的第二条记录是从offset 8159开始的...

BBED> dump /v dba 4, 404 offset 8159
File:
/u01/app/oracle/oradata/orcl/users01.dbf (4)
Block:
404 Offsets: 8159 to 8191 Dba:0x01000194
-------------------------------------------------------
2c020202 c1030a48 656c6c6f 4672616e l ,...�..HelloFran
6b2c0102 02c10205 4672616e 6b0206ec l k,...�..Frank..
28 l (

<
16 bytes per line>

BBED
> dump /v dba 4, 404 offset 8166
File:
/u01/app/oracle/oradata/orcl/users01.dbf (4)
Block:
404 Offsets: 8166 to 8191 Dba:0x01000194
-------------------------------------------------------
48656c6c 6f467261 6e6b2c01 0202c102 l HelloFrank,...�.
05467261 6e6b0206 ec28 l .Frank..

<
16 bytes per line>

BBED
>

现在尝试把'HelloFrank'改成'Fraud'试一下...

BBED> modify /c Fraud dba 4, 404 offset 8166
BBED
-00215: editing not allowed in BROWSE mode


BBED
> set mode edit
MODE Edit

BBED
> modify /c Fraud dba 4, 404 offset 8166
Warning: contents of previous BIFILE will be lost. Proceed
? (Y/N) Y
File:
/u01/app/oracle/oradata/orcl/users01.dbf (4)
Block:
404 Offsets: 8166 to 8191 Dba:0x01000194
------------------------------------------------------------------------
46726175 64467261 6e6b2c01 0202c102 05467261 6e6b0206 ec28

<
32 bytes per line>

BBED
> dump /v dba 4, 404 offset 8166
File:
/u01/app/oracle/oradata/orcl/users01.dbf (4)
Block:
404 Offsets: 8166 to 8191 Dba:0x01000194
-------------------------------------------------------
46726175 64467261 6e6b2c01 0202c102 l FraudFrank,...�.
05467261 6e6b0206 ec28 l .Frank..

<
16 bytes per line>

可以看到'Fraud'不会把'HelloFrank'都替换掉,只是'Fraud'这5个字符覆盖了'Hello'这5个字符。

那如果用'I am Frank!'这个字符串替换'HelloFrank'呢? (注意到需要用引号把I am Frank!给括起来)

BBED> modify /c I am Frank! dba 4, 404 offset 8166
BBED
-00207: invalid offset specifier (am)


BBED
> modify /c "I am Frank!" dba 4, 404 offset 8166
File:
/u01/app/oracle/oradata/orcl/users01.dbf (4)
Block:
404 Offsets: 8166 to 8191 Dba:0x01000194
------------------------------------------------------------------------
4920616d
20467261 6e6b2101 0202c102 05467261 6e6b0206 ec28

<
32 bytes per line>

BBED
> dump /v dba 4, 404 offset 8166
File:
/u01/app/oracle/oradata/orcl/users01.dbf (4)
Block:
404 Offsets: 8166 to 8191 Dba:0x01000194
-------------------------------------------------------
4920616d
20467261 6e6b2101 0202c102 l I am Frank!...�.
05467261 6e6b0206 ec28 l .Frank..

<
16 bytes per line>

BBED
>

从dump结果来看,数据块被修改了,那么用SQL来访问表的结果是什么呢?

SQL> alter system flush buffer_cache;

System altered.

SQL
> select * from test;

ID NAME
---------- ----------
2 I am Frank

这个结果很奇怪,第一行数据(1, ’Frank')丢失了! 而且注意Name为(I am Frank), 少了一个感叹号(!).

因为Name这一列的数据类型是varchar2(10), 最大是10个字符,而我通过BBED写入了11个字符,把下一行数据(也就是表中的第一行数据(1, 'Frank'))的开始部分的标志位的信息给覆盖掉了!!因此SQL语句不能正确读出第一行数据了,造成了数据的丢失!!

从这个案例也可以看出用BBED一定要小心再小心, 很容易就可以把一个block给破坏了!

posted @ 2011-02-19 00:24  FangwenYu  阅读(603)  评论(0编辑  收藏  举报