当前位置: 移动技术网 > IT编程>数据库>MSSQL > Sql server中内部函数fn_PhysLocFormatter存在解析错误详解

Sql server中内部函数fn_PhysLocFormatter存在解析错误详解

2017年10月07日  | 移动技术网IT编程  | 我要评论

138译码器,千金笑19楼,长春房价走势

前言

有网友指出,sql server 2012中fn_physlocformatter内部函数在解析数据行记录位置时存在错误,见:http://www.itpub.net/thread-1751655-1-1.html,实际测试后发现,一是2008r2中同样存在问题,二是不仅页号解析存在问题,槽号解析也存在同样问题。

下面先查看表nt_siteinfo的数据行记录位置。

select siteid,%%physloc%%,sys.fn_physlocformatter(%%physloc%%) from nt_siteinfo

siteid

%%physloc%%

sys.fn_physlocformatter(%%physloc%%)

1

0xe900000001000000

(1:59648:0)

23

0xe900000001000100

(1:59648:1)

24

0xe900000001000200

(1:59648:2)

 

......

 

149

0xe900000001007f00

(1:59648:127)

150

0xe900000001008000

(1:59648:128)

151

0xe900000001008100

(1:59648:33024)

152

0xe900000001008200

(1:59648:33280)

 

......

 

226

0xe90000000100cc00

(1:59648:52224)

227

0xe90000000100cd00

(1:59648:52480)

228

0x4b02000001000000

(1:587:0)

229

0x4b02000001000100

(1:587:1)

 

......

 

360

0x4b02000001007f00

(1:587:127)

361

0x4b02000001008000

(1:587:128)

362

0x4b02000001008100

(1:587:33024)

363

0x4b02000001008200

(1:587:33280)

 

......

 

422

0x4b0200000100bd00

(1:587:48384)

423

0x4b0200000100be00

(1:587:48640)

424

0x3c05000001000000

(1:1340:0)

425

0x3c05000001000100

(1:1340:1)

 

......

 

552

0x3c05000001008000

(1:1340:128)

553

0x3c05000001008100

(1:1340:33024)

 

 

 

596

0x3c0500000100ac00

(1:1340:44032)

597

0x9978000001000000

(1:39288:0)

 

......

 

658

0x9978000001003d00

(1:39288:61)

下面查看表nt_siteinfo分配的数据页情况。

dbcc ind(wjgk,nt_siteinfo,0)

pagepid

iamfid

iampid

pagetype

indexlevel

nextpagepid

prevpagepid

238

null

null

10

null

0

0

233

1

238

1

0

587

0

587

1

238

1

0

1340

233

1340

1

238

1

0

30873

587

30873

1

238

1

0

0

1340

microsoft未公开的伪列%%physloc%%,类型为binary(8),返回表中记录的rowid,格式是:前4字节表示页号,中间2字节表示文件号,最后2字节表示槽号。

对照上面的实际数据,可以发现sys.fn_physlocformatter在解析记录位置时,既有采用高字节在前的big_endian格式,又有采用低字节在前的little_endian格式,造成采用高字节在前的big_endian格式解析的数据错误:

页号解析:
e9000000解析为59648(e900),错误,实际应为233(e9)

4b020000解析为576(24b),正确

3c050000解析为1340(53c),正确

99780000解析为39288(9978),错误,实际应为30873(7899)

槽号解析:

8000解析为128(0080),正确

8100解析为33024(8100),错误,应为129(0081)

下面给出错误原因。

先看下sys.fn_physlocformatter函数的定义:

select object_definition(object_id('sys.fn_physlocformatter'))
go
 
-------------------------------------------------------------------------------
-- name: sys.fn_physlocformatter
--
-- description:
-- formats the output of %%physloc%% virtual column
--
-- notes:
-------------------------------------------------------------------------------
create function sys.fn_physlocformatter (@physical_locator binary (8))
 returns varchar (128)
as
 begin
 declare @page_id binary (4)
 declare @file_id binary (2)
 declare @slot_id binary (2)
 -- page id is the first four bytes, then 2 bytes of page id, then 2 bytes of slot
 --
 select @page_id = convert (binary (4), reverse (substring (@physical_locator, 1, 4)))
 select @file_id = convert (binary (2), reverse (substring (@physical_locator, 5, 2)))
 select @slot_id = convert (binary (2), reverse (substring (@physical_locator, 7, 2)))
 return '(' + cast (cast (@file_id as int) as varchar) + ':'
 + cast (cast (@page_id as int) as varchar) + ':'
 + cast (cast (@slot_id as int) as varchar) + ')'
 end

再看下reverse函数:

select reverse('工人')
----
人工
 
(1 行受影响)
 
select reverse('12345工人')
---------
人工54321
 
(1 行受影响)
 
select reverse('工12345人')
---------
人54321工
 
(1 行受影响)

结论:问题出在reverse函数上。

reverse函数的作用是字符反转,而不是字节反转,当遇到81-fe之间的字节时,被认为是双字节字符而组合在一起参与反转操作,造成了错误。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对移动技术网的支持。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网