接着解析数据文件(一)
BBED> p rowdata <=======这个就是需要解析的数据了
ub1 rowdata[0] @8119 0x2c
ub1 rowdata[1] @8120 0x01
ub1 rowdata[2] @8121 0x03
ub1 rowdata[3] @8122 0x02
ub1 rowdata[4] @8123 0xc1
ub1 rowdata[5] @8124 0x04
ub1 rowdata[6] @8125 0x08
ub1 rowdata[7] @8126 0x68
ub1 rowdata[8] @8127 0x65
ub1 rowdata[9] @8128 0x68
ub1 rowdata[10] @8129 0x65
ub1 rowdata[11] @8130 0x68
ub1 rowdata[12] @8131 0x65
ub1 rowdata[13] @8132 0x68
ub1 rowdata[14] @8133 0x65
ub1 rowdata[15] @8134 0x07
ub1 rowdata[16] @8135 0x78
ub1 rowdata[17] @8136 0x77
ub1 rowdata[18] @8137 0x03
ub1 rowdata[19] @8138 0x12
ub1 rowdata[20] @8139 0x16
ub1 rowdata[21] @8140 0x37
ub1 rowdata[22] @8141 0x02
ub1 rowdata[23] @8142 0x2c
ub1 rowdata[24] @8143 0x01
ub1 rowdata[25] @8144 0x03
ub1 rowdata[26] @8145 0x02
ub1 rowdata[27] @8146 0xc1
ub1 rowdata[28] @8147 0x03
ub1 rowdata[29] @8148 0x08
ub1 rowdata[30] @8149 0x78
ub1 rowdata[31] @8150 0x69
ub1 rowdata[32] @8151 0x61
ub1 rowdata[33] @8152 0x6f
ub1 rowdata[34] @8153 0x68
ub1 rowdata[35] @8154 0x6f
ub1 rowdata[36] @8155 0x6e
ub1 rowdata[37] @8156 0x67
ub1 rowdata[38] @8157 0x07
ub1 rowdata[39] @8158 0x78
ub1 rowdata[40] @8159 0x77
ub1 rowdata[41] @8160 0x03
ub1 rowdata[42] @8161 0x12
ub1 rowdata[43] @8162 0x16
ub1 rowdata[44] @8163 0x36
ub1 rowdata[45] @8164 0x3a
ub1 rowdata[46] @8165 0x2c
ub1 rowdata[47] @8166 0x01
ub1 rowdata[48] @8167 0x03
ub1 rowdata[49] @8168 0x02
ub1 rowdata[50] @8169 0xc1
ub1 rowdata[51] @8170 0x02
ub1 rowdata[52] @8171 0x08
ub1 rowdata[53] @8172 0x78
ub1 rowdata[54] @8173 0x69
ub1 rowdata[55] @8174 0x61
ub1 rowdata[56] @8175 0x6f
ub1 rowdata[57] @8176 0x6d
ub1 rowdata[58] @8177 0x69
ub1 rowdata[59] @8178 0x6e
ub1 rowdata[60] @8179 0x67
ub1 rowdata[61] @8180 0x07
ub1 rowdata[62] @8181 0x78
ub1 rowdata[63] @8182 0x77
ub1 rowdata[64] @8183 0x03
ub1 rowdata[65] @8184 0x12
ub1 rowdata[66] @8185 0x16
ub1 rowdata[67] @8186 0x36
ub1 rowdata[68] @8187 0x36
这里的问题就是怎么能定位到rowdata数据的位置,并且rowdata的数据怎么转换成表的内容。
一个块的前20字节是块头信息,然后是一个固定的24位的事物信息 + 24*事物槽个数 + 14的表记录信息和空间使用信息 + kdbt*4(一个表占4个字节)+ kdbr*2(一个表占用2个字节)+freespace之后的位置就是数据真正的起始位置
所以真正的数据是从20+24+24*ktbbhict+14+kdbt*4+kdbr*2+8+freespace之后开始算起。
其中freespace = kdbhfseo - kdbhfsbo
block1表的第一行数据说明如下:
tl: 23 fb: --H-FL-- lb: 0x1 cc: 3 <========第三行数据
col 0: [ 2] c1 04
col 1: [ 8] 68 65 68 65 68 65 68 65
col 2: [ 7] 78 77 03 12 16 37 02
数据的组成格式如下:
fb: --H-FL--标志 <====128 64 32 16 8 4 2 1 所以--H-FL-- = 32+8+4 = 44,转换成16进制为 2c,如果数据已经被删除,则为--HDFL- = 32+16+8+4 = 60转换成16进制为3c
lb: 0x1 <==== 事物槽标志
cc: 3 <==== 该行数据有多少列
下面就是真正数据
col 0: [ 2] c1 04
col 1: [ 8] 68 65 68 65 68 65 68 65
col 2: [ 7] 78 77 03 12 16 37 02
其中 col 0:[2] 2代表该列长度是2,其他同理。
然后查看rowdata的数据
ub1 rowdata[0] @8119 0x2c <====对应fb --H-FL--标志 = 44 16进制是2c
ub1 rowdata[1] @8120 0x01 <====对应lb: 0x1
ub1 rowdata[2] @8121 0x03 <====cc: 3 有3列数据
ub1 rowdata[3] @8122 0x02 <====col 0: [2] 长度=2
ub1 rowdata[4] @8123 0xc1
ub1 rowdata[5] @8124 0x04
ub1 rowdata[6] @8125 0x08 <====col 1: [8] 长度=8
ub1 rowdata[7] @8126 0x68
ub1 rowdata[8] @8127 0x65
ub1 rowdata[9] @8128 0x68
ub1 rowdata[10] @8129 0x65
ub1 rowdata[11] @8130 0x68
ub1 rowdata[12] @8131 0x65
ub1 rowdata[13] @8132 0x68
ub1 rowdata[14] @8133 0x65
ub1 rowdata[15] @8134 0x07 <=====col 2: [7] 长度=7
ub1 rowdata[16] @8135 0x78
ub1 rowdata[17] @8136 0x77
ub1 rowdata[18] @8137 0x03
ub1 rowdata[19] @8138 0x12
ub1 rowdata[20] @8139 0x16
ub1 rowdata[21] @8140 0x37
ub1 rowdata[22] @8141 0x02
索引rowdata的数据格式为:
fb+lb+cc+(列数据) + fb+lb+cc+(列数据) 。。。。。,其中fb+lb+cc+(列数据)可以理解为一行数据。
实现的C代码(仅列出了重要的实现部分)如下:
scandata(uaddress,ulength)
{
<===变量定义省略
read( fd, buffer, 20 );
memcpy(&kcbh,buffer,20);
read(fd, buffer, 24);
memcpy(&ktbbh,buffer,24);
/*
typedef struct ktbbh{
ub4 ktbbhtyp;
ub2 ktbbhsg1;
ub2 ktbbhod1;
ub4 kscnbas;
ub4 kscnwrp;
ub2 ktbbhict;
ub1 ktbbhflg;
ub1 ktbbhfsl;
ub4 ktbbhfnx;
}KTBBH;
*/
lseek( fd, BLOCK * k +20+24+ktbbh.ktbbhict*24, SEEK_SET );
read(fd, buffer, 14 );
memcpy(&kdbh, buffer, 14 );
/*
typedef struct kdbh {
ub1 kdbhflag;
ub1 kdbhntab; <===获取表个数
ub2 kdbhnrow; <===行数
ub2 kdbhfrre;
ub2 kdbhfsbo;
ub2 kdbhfseo;
ub2 kdbhavsp;
ub2 kdbhtosp;
}KDBH;
*/
//ktbbh.ktbbhtyp=1代表是数据块, = 2代表是索引, checkaddress块的地址要再段头的一级块位图的范围
if(nrow>0 && kcbh.type_kcbh==6 && ktbbh.ktbbhtyp==1 && checkaddress>=address && checkaddress<=(address+len-1))
{
lseek( fd, 0, SEEK_SET );
lseek(fd,BLOCK*k+kdbh.kdbhntab*4+kdbh.kdbhnrow*2+kdbh.kdbhfseo-kdbh.kdbhfsbo+20+14+24+24*ktbbh.ktbbhict+8, SEEK_SET);
printf("k=%d kdbhntab=%d kdbhnrow=%d seo=%d sbo=%d\n", k, kdbh.kdbhntab, kdbh.kdbhnrow, kdbh.kdbhfseo,kdbh.kdbhfsbo);
for ( i = 0; i < kdbh.kdbhnrow; i++ ) <====一共有多少行数据
{
read( fd, buffer, 3 ); //获取fb+lb+cc
memcpy( &rowdata_header, buffer, 3 );
/*
typedef struct rowdata_header {
ub1 fb;
ub1 transaction;
ub1 column_count;
}ROWDATA_HEADER;
*/
printf( "columns_count=%d\n", rowdata_header.column_count );
if(rowdata_header.column_count>0) <====有多少列循环多少次
{
if(rowdata_header.flag!=60) <=====60代表3c,代表数据已经被删除,删除的数据就不需要输出了
{
for(cnt=0; cnt < rowdata_header.column_count; cnt++)
{
read( fd, buffer, 1 ); //cc下面的值,第一个代表该列有多长
memcpy( &length, buffer, 1 );
read( fd, data, length );
for ( j = 0; j < length; j++ ) //把该列的值保存起来
{
sprintf(temp+j*2,"%02x",*(data+j));
}
printf("%s\n", temp);
}
}
}
}
}
5、解析结果
这个时候解析表空间tablespace t 对应的数据文件'/u01/app/oradata/QXY/t.dbf'。
备注:c语言读取来的数据不一定是有序的
看程序的输出结果
[oracle@QXY1 jiexi]$ ./header | more
objectid=134673 <=====对象号134673 ,代表block1
address++++++++++++3400080 length=8 <=====address = 3400080就是L的地址,长度是8
k=131 kdbhntab=1 kdbhnrow=3 kdbhfseo=8019 kdbhfsbo=24 <=====对应kdbh的数据, k=131 代表在哪个块。kdbhnrow该块有3行数据kdbhfseo-kdbhfsbo = freespace
columns_count=3
****col0****length= 2****value****=c104 <====真正的数据
****col1****length= 8****value****=6865686568656865
****col2****length= 7****value****=78770312163702
columns_count=3
****col0****length= 2****value****=c103
****col1****length= 8****value****=7869616f686f6e67
****col2****length= 7****value****=7877031216363a
columns_count=3
****col0****length= 2****value****=c102
****col1****length= 8****value****=7869616f6d696e67
****col2****length= 7****value****=78770312163636
objectid=134674 <======对象号134674 代码block2
address++++++++++++3400088 length=8
k=139 kdbhntab=1 kdbhnrow=2 kdbhfseo=7944 kdbhfsbo=22 <=====block2的数据在139块
columns_count=2
****col0****length= 2****value****=c104
****col1****length= 58****value****=100540001020c80000002000000010000006f42d200440900000000000034000000000001006100620063006400650066006700680069006a006b006c
006d006e006f0070007100720073007400750076007700780079007a
columns_count=2
****col0****length= 2****value****=c103
****col1****length= 2a****value****=100540001020c80000002000000010000006f42d100160900000000000006000000000001006100620063
objectid=134677 <=====134677对象号134677 代表block3
address++++++++++++34000a0 length=8
k=163 kdbhntab=1 kdbhnrow=242 kdbhfseo=1315 kdbhfsbo=502
columns_count=2
****col0****length= 3****value****=c23402
****col1****length= 14****value****=7971686b7a70716a6f746c686865686672787767
columns_count=2
****col0****length= 3****value****=c23403
****col1****length= 14****value****=1706165666a6c65727a746d7077696f7577796872
columns_count=2
****col0****length= 3****value****=c23404
****col1****length= 14****value****=16e707972796277736561786b73757868636d6279
columns_count=2
****col0****length= 3****value****=c23405
****col1****length= 14****value****=169637a6c63616265646f78666e75796e6361796e
columns_count=2
****col0****length= 3****value****=c23406
****col1****length= 14****value****=16d6362726e6a777a757174656267647070617662
columns_count=2
****col0****length= 3****value****=c23407
****col1****length= 14****value****=17174787276767976767675706f6471766d766c78
--More--
其实上面的这些数据就是oracle块中的表数据块了。
比如131块
buffer tsn: 15 rdba: 0x03400083 (13/131)
scn: 0x0000.01cf22fc seq: 0x01 flg: 0x06 tail: 0x22fc0601
frmt: 0x02 chkval: 0xee46 type: 0x06=trans data
Hex dump of block: st=0, typ_found=1
。
。
对应的数据
tab 0, row 0, @0x1f81
tl: 23 fb: --H-FL-- lb: 0x1 cc: 3
col 0: [ 2] c1 02
col 1: [ 8] 78 69 61 6f 6d 69 6e 67
col 2: [ 7] 78 77 03 12 16 36 36
tab 0, row 1, @0x1f6a
tl: 23 fb: --H-FL-- lb: 0x1 cc: 3
col 0: [ 2] c1 03
col 1: [ 8] 78 69 61 6f 68 6f 6e 67
col 2: [ 7] 78 77 03 12 16 36 3a
tab 0, row 2, @0x1f53
tl: 23 fb: --H-FL-- lb: 0x1 cc: 3
col 0: [ 2] c1 04
col 1: [ 8] 68 65 68 65 68 65 68 65
col 2: [ 7] 78 77 03 12 16 37 02
139块的数据(其实就是block2的数据)
Block dump from disk:
buffer tsn: 15 rdba: 0x0340008b (13/139)
scn: 0x0000.01cf2342 seq: 0x01 flg: 0x06 tail: 0x23420601
frmt: 0x02 chkval: 0x179d type: 0x06=trans data
.
.
.
ntab=1
nrow=2
frre=-1
fsbo=0x16
fseo=0x1f08
avsp=0x1ef2
tosp=0x1ef2
0xe:pti[0] nrow=2 offs=0
0x12:pri[0] offs=0x1f67
0x14:pri[1] offs=0x1f08
block_row_dump:
tab 0, row 0, @0x1f67
tl: 49 fb: --H-FL-- lb: 0x1 cc: 2
col 0: [ 2] c1 03
col 1: [42]
00 54 00 01 02 0c 80 00 00 02 00 00 00 01 00 00 00 6f 42 d1 00 16 09 00 00
00 00 00 00 06 00 00 00 00 00 01 00 61 00 62 00 63
LOB
Locator:
Length: 84(42)
Version: 1
Byte Length: 2
LobID: 00.00.00.01.00.00.00.6f.42.d1
Flags[ 0x02 0x0c 0x80 0x00 ]:
Type: CLOB
Storage: BasicFile
Enable Storage in Row
Characterset Format: IMPLICIT
Partitioned Table: No
Options: VaringWidthReadWrite
Inode:
Size: 22
Flag: 0x09 [ Valid DataInRow ]
Future: 0x00 (should be '0x00')
Blocks: 0
Bytes: 6
Version: 00000.0000000001
Inline data[6]
Dump of memory from 0x00007F70A900F9F6 to 0x00007F70A900F9FC
7F70A900F9F0 61000100 63006200 [...a.b.c]
tab 0, row 1, @0x1f08
tl: 95 fb: --H-FL-- lb: 0x1 cc: 2
col 0: [ 2] c1 04
col 1: [88]
00 54 00 01 02 0c 80 00 00 02 00 00 00 01 00 00 00 6f 42 d2 00 44 09 00 00
00 00 00 00 34 00 00 00 00 00 01 00 61 00 62 00 63 00 64 00 65 00 66 00 67
00 68 00 69 00 6a 00 6b 00 6c 00 6d 00 6e 00 6f 00 70 00 71 00 72 00 73 00
74 00 75 00 76 00 77 00 78 00 79 00 7a
LOB
Locator:
Length: 84(88)
Version: 1
Byte Length: 2
LobID: 00.00.00.01.00.00.00.6f.42.d2
Flags[ 0x02 0x0c 0x80 0x00 ]:
Type: CLOB
Storage: BasicFile
Enable Storage in Row
Characterset Format: IMPLICIT
Partitioned Table: No
Options: VaringWidthReadWrite
Inode:
Size: 68
Flag: 0x09 [ Valid DataInRow ]
Future: 0x00 (should be '0x00')
Blocks: 0
Bytes: 52
Version: 00000.0000000001
Inline data[52]
Dump of memory from 0x00007F70A900F997 to 0x00007F70A900F9CB
7F70A900F990 00010000 00620061 00640063 [....a.b.c.d.]
7F70A900F9A0 00660065 00680067 006A0069 006C006B [e.f.g.h.i.j.k.l.]
7F70A900F9B0 006E006D 0070006F 00720071 00740073 [m.n.o.p.q.r.s.t.]
7F70A900F9C0 00760075 00780077 2C7A0079 [u.v.w.x.y.z,]
end_of_block_dump
End dump data blocks tsn: 15 file#: 13 minblk 139 maxblk 139
可以看到139块的数据和解析出来的是一样的
k=139 kdbhntab=1 kdbhnrow=2 kdbhfseo=7944 kdbhfsbo=22
columns_count=2
****col0****length= 2****value****=c104
****col1****length= 58****value****=100540001020c80000002000000010000006f42d200440900000000000034000000000001006100620063006400650066006700680069006a006b006c
006d006e006f0070007100720073007400750076007700780079007a
columns_count=2
****col0****length= 2****value****=c103
****col1****length= 2a****value****=100540001020c80000002000000010000006f42d100160900000000000006000000000001006100620063
k=163 kdbhntab=1 kdbhnrow=242 kdbhfseo=1315 kdbhfsbo=502
163块的数据(block3有20000行数据,163块只有该表的242行数据)
验证如下:
Block dump from disk:
buffer tsn: 15 rdba: 0x034000a3 (13/163)
scn: 0x0000.01cf2b9f seq: 0x01 flg: 0x06 tail: 0x2b9f0601
frmt: 0x02 chkval: 0xc9e1 type: 0x06=trans data
Hex dump of block: st=0, typ_found=1
Dump of memory from 0x00007FB0A2E69A00 to 0x00007FB0A2E6BA00
。。
。。
。。
data_block_dump,data header at 0x7fb0a2e69a64
===============
tsiz: 0x1f98
hsiz: 0x1f6
pbl: 0x7fb0a2e69a64
76543210
flag=--------
ntab=1
nrow=242 <=====242行数据
frre=-1
fsbo=0x1f6
fseo=0x523
avsp=0x32d
tosp=0x32d
.
.
.
col 0: [ 3] c2 34 02
col 1: [20] 79 71 68 6b 7a 70 71 6a 6f 74 6c 68 68 65 68 66 72 78 77 67
tab 0, row 16, @0x53f
tl: 28 fb: --H-FL-- lb: 0x1 cc: 2
col 0: [ 3] c2 34 03
col 1: [20] 70 61 65 66 6a 6c 65 72 7a 74 6d 70 77 69 6f 75 77 79 68 72
tab 0, row 17, @0x55b
tl: 28 fb: --H-FL-- lb: 0x1 cc: 2
col 0: [ 3] c2 34 04
col 1: [20] 6e 70 79 72 79 62 77 73 65 61 78 6b 73 75 78 68 63 6d 62 79
tab 0, row 18, @0x577
tl: 28 fb: --H-FL-- lb: 0x1 cc: 2
col 0: [ 3] c2 34 05
col 1: [20] 69 63 7a 6c 63 61 62 65 64 6f 78 66 6e 75 79 6e 63 61 79 6e
tab 0, row 19, @0x593
tl: 28 fb: --H-FL-- lb: 0x1 cc: 2
col 0: [ 3] c2 34 06
col 1: [20] 6d 63 62 72 6e 6a 77 7a 75 71 74 65 62 67 64 70 70 61 76 62
tab 0, row 20, @0x5af
tl: 28 fb: --H-FL-- lb: 0x1 cc: 2
col 0: [ 3] c2 34 07
col 1: [20] 71 74 78 72 76 76 79 76 76 76 75 70 6f 64 71 76 6d 76 6c 78
.
.
.
对应解析的部分数据
k=163 kdbhntab=1 kdbhnrow=242 kdbhfseo=1315 kdbhfsbo=502
columns_count=2
****col0****length= 3****value****=c23402
****col1****length= 14****value****=7971686b7a70716a6f746c686865686672787767
columns_count=2
****col0****length= 3****value****=c23403
****col1****length= 14****value****=706165666a6c65727a746d7077696f7577796872
columns_count=2
****col0****length= 3****value****=c23404
****col1****length= 14****value****=6e707972796277736561786b73757868636d6279
columns_count=2
****col0****length= 3****value****=c23405
****col1****length= 14****value****=69637a6c63616265646f78666e75796e6361796e
columns_count=2
****col0****length= 3****value****=c23406
****col1****length= 14****value****=6d6362726e6a777a757174656267647070617662
columns_count=2
****col0****length= 3****value****=c23407
****col1****length= 14****value****=7174787276767976767675706f6471766d766c78
--More--
可以随机抽取一个验证,比如下面的一行数据
columns_count=2
****col0****length= 3****value****=c23407
****col1****length= 14****value****=7174787276767976767675706f6471766d766c78
SQL>
SQL> select display_raw('c23407','NUMBER') from dual;
DISPLAY_RAW('C23407','NUMBER')
--------------------------------------------------------
5106
SQL> select display_raw('7174787276767976767675706f6471766d766c78','VARCHAR2') from dual;
DISPLAY_RAW('7174787276767976767675706F6471766D766C78','VARCHAR2')
---------------------------------------------------------------------------
qtxrvvyvvvupodqvmvlx
SQL>
SQL> select * from block3 where age = 5106; <=====数据都是正确的
AGE NAME
---------- --------------------
5106 qtxrvvyvvvupodqvmvlx
SQL>
这些数据属于哪个表,表列的名字叫什么, 列是属于什么类型,需要解析system表空间的数据文件才能得到。到这里为止只是把表的数据解析出来,但是怎么把这些数据转换成能看懂的数据,这个就需要配合system数据文件,关于system数据文件的解析下次分享再介绍。
目前配合解析的system表空间得到最终效果如下:
[oracle@QXY1 proc]$ ./block > block.txt
[oracle@QXY1 proc]$
[oracle@QXY1 proc]$ cat block.txt
当前对象号134673 name = bock1
ID,NAME,CURDATE
3 hehehehe 2019-03-18 21:54:01
2 xiaohong 2019-03-18 21:53:57
1 xiaoming 2019-03-18 21:53:53
当前对象号134674 name = bock2
ID,NAME
3 abcdefghijklmnopqrstuvwxyz
2 abc
当前对象号134677 name = bock3
AGE,NAME
5101 yqhkzpqjotlhhehfrxwg
5102 paefjlerztmpwiouwyhr
5103 npyrybwseaxksuxhcmby
5104 iczlcabedoxfnuyncayn
5105 mcbrnjwzuqtebgdppavb
5106 qtxrvvyvvvupodqvmvlx
5107 qvieuavcuupsuvehyami
5108 fqojtjzocomgvegkustq
5109 qnnpryxmdddrmagkeisw
5110 pijpyvdpoyyonaywplww
5111 ndfoptrznyhjbdgojreg
5112 wvbrebnbmchsmylebapl
5113 ulypbedxrdcmhxnrftqb
5114 wyszxtocdwadcdvyaeow
5115 eqntavjrrcgxyilrensf
5116 bebugykhbcnkjeuwtcqo
5117 vuacelvgrodbipqloyab
5118 xxbbgbuskcgzisifqxay
.
.
.
.
下次分享会介绍数据是怎么转换成可读的,并且数据属于哪个表,表列叫什么等等。。