Error: 9561的一种处理方法
本文的目的在于给出一种方法(或者workaround)来屏蔽错误Error: 9561。
在老环境ASE 12.5上测试某程序时,执行一些命令会报Error: 9561!
环境介绍:
ASE版本为: Adaptive Server Enterprise/12.5/SWR 9616 GA/P/NT (IX86)/OS 4.0/main/1647/32-bit/OPT/Fri Jun 01 16:58:25 2001
此版本为ASE 12.5 GA,裸奔很久了。
lock scheme=allpages
系统库model、tempdb以及用户数据库均启用了选项:allow nulls by default
现象描述:
使用存储过程sp_helpindex查看表上的索引信息时,会报Error:9561。
1> sp_helpindex sysobjects
2> go
Msg 9561, Level 20, State 5:
Server 'TEST', Procedure 'sp_helpindex', Line 306:
An insert or update to table '#spindtab____01000430020573012' places column 'maxrowsperpage' at offset 2, ending at offset 4. The maximum permitted ending offset for this column is 2. This is a server internal error.
Msg 9561, Level 20, State 5:
Server 'TEST', Procedure 'sp_helpindex', Line 306:
An insert or update to table '#spindtab____01000430020573012' places column 'maxrowsperpage' at offset 2, ending at offset 4. The maximum permitted ending offset for this column is 2. This is a server internal error.
index_name index_description index_keys
-------------------- -------------------------------------------------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------(0 rows affected)
(return status = 0)
执行存储过程sp_helprotect查看对象权限分配信息时,也报类似的Error:9561。
1>sp_helprotect dbo
2>go
Msg 9561, Level 20, State 5:
Server 'TEST', Procedure 'sp_helprotect', Line 299:
An insert or update to table '#sysprotects201000430020573012' places column 'id' at offset 2, ending at offset 6. The maximum permitted ending offset for this column is 2. This is a server internal error.
分析过程
根据Error:9561的错误信息描述,曾经怀疑某系统表中某字段的偏移信息出现了差错。
在网上搜索一下CR: 389129( 来源于:Targeted CR List for ASE 15.0 ESD #2 )
Error 511 "Attempt to update or insert row failed because resultant row of size < value > bytes is larger than the maximum size ( < value > bytes) allowed for this table..." may be raised during the execution of a stored procedure using the reformatting strategy and the creation of a DOL (Datarows Only Locking) work table. Alternatively the error 9561 "An insert or update to table 'temp worktable' places column '(unknown column)' at offset < value > ..." may be raised.
很奇怪,我的ASE12.5配置的lock scheme为allpages,怎么会自动创建DOL类型的工作表呢?
浏览存储过程sp_helpindex的源代码,发现一张临时表#spindtab的创建语句:
create table #spindtab
(
index_name varchar(30),
index_keys varchar(1024),
index_description varchar(68),
index_max_rows_per_page smallint,
index_fillfactor smallint,
index_reservepagegap smallint,
index_created datetime NULL
)
Error:9561信息中显示的#spindtab____01000430020573012就是指的存储过程sp_helpindex中创建的临时表#spindtab!
此处你需要了解一下会话临时表的命名规则,可以参考Rob V.的文章:Reading temporary tables that aren't yours
再继续追踪列名:maxrowsperpage,找到这样一条语句:
insert into #spindtab
select name, @keys, @inddesc, maxrowsperpage, fill_factor,
isnull(res_page_gap ,0), crdate
from sysindexes
where id = object_id(@objname)
and indid = @indid
查看一下列maxrowsperpage在表sysindexes中的偏移情况:
1> select colid,name,offset,length from syscolumns where id= 2 and name='maxrowsperpage'
2> go
colid name offset length
------ ------------------------------ ------ -----------
16 maxrowsperpage 48 2
列maxrowsperpage在sysindexes处于第16个位置,偏移48字节,好像和Error:9561提示的offset:2没有什么关系。
再来看看临时表#spindtab中的第4个字段: index_max_rows_per_page,它的类型是:smallint,占用2字节。和Error:9561提示的开始偏移2,结束偏移4可能有点关系!
字段index_max_rows_per_page前面的3个字段都是varchar类型,都是属于变长类型字段;
如果index_max_rows_per_page存储在offset=2位置处的话,必要要求index_max_rows_per_page定义为NOT NULL,表#spindtab的定义语句中没有指定NOT NULL或者NULL。这是问题所在!
解决方法
关闭临时数据库、model上的选项:allow nulls by default;
将lock scheme设置成datarows,Error:9561的错误信息就变成:
An insert or update to table '#spindtab____01000430020573012' places column 'maxrowsperpage' at offset 6, ending at offset 8. The maximum permitted ending offset for this column is 6. This is a server internal error.
本文的关键信息
1、选项:allow nulls by default会影响没有显示指定是否为空字段的为空属性;
2、一个字段是否为空,在行内的存储位置是不同的;
3、DOL表与APL表的初始offset值不同;