文本版|topic 高级搜索
   名人堂 帮助 论坛制度 意见反馈 | 首页 博客 周新贴 专题 求职 读书
RSS 底部
 
社区导航: 专家门诊   网络技术   操作系统   数据库   程序设计   系统应用   考试认证   CIO及信息化   站长交流   综合交流   下载基地  51CTO产品服务 设为首页 | 收藏本站
51CTO技术论坛» MySQL & PostgreSQL & Sybase » 对ASE系统存储过程的剖析-sp_who       [ 打印]  [ 订阅]  [ 收藏]  [ 推荐给朋友]   [ 本帖文本页]

论坛跳转:
     
标题: [转载] 对ASE系统存储过程的剖析-sp_who  ( 查看:720  回复:1 )   
 
lllenxue
副版主  点击可查看详细


十二生肖之狗   双子座   行业勋章   技术勋章   诚信兄弟  
帖子 701
精华 3
无忧币 2912
积分 1089
阅读权限 140
注册日期 2007-3-23
最后登录 2008-8-29 离线

[查看资料]  [发短消息]  [Blog
  QQ       
发表于:2007-9-27 18:43   标题:对ASE系统存储过程的剖析-sp_who
上一帖 |
昨晚有空,把 sybase 系统过程 sp_who , DDL 后分析了一下,全文如下:








-- 以下是 DDL 出来的内容:


-----------------------------------------------------------------------------


-- DDL for Stored procedure 'sybsystemprocs.dbo.sp_who'


-----------------------------------------------------------------------------


-- 以上是注释





print 'Creating Stored procedure sp_who'


go


-- 上面两句是显示一句话, go 是执行(下同)





use sybsystemprocs


go


-- 选择将要使用的数据库(存储过程建在什么数据库里)





setuser 'dbo'


go


-- 使当前用户充当 'dbo





-- 以下是存储过程的实体


/* Sccsid = "%Z% generic/sproc/%M% %I% %G%" */


/* 4.8 1.1 06/14/90 sproc/src/serveroption */





/*


** Messages for "sp_who" 17nnn


**


** 17231, "No login with the specified name exists."


*/


-- 以上是注释





create procedure sp_who @loginame varchar(30) = NULL as


-- 创建存储过程 sp_who) 的参数 loginame





declare @low int


declare @high int


declare @spidlow int


declare @spidhigh int


declare @len1 int, @len2 int, @len3 int


-- 申明了若干变量





if @@trancount = 0


--@@ 开头的都是系统全局变量


--@@trancount 是用来检查事务嵌套级别的全局变量,批处理中每个 begin transaction 将事务计数加 1


begin


set chained off


-- 用在会话开始和事务结束时使用,指示是否在第一个数据检索或数据修改语句前开始一个事务(是否在 delte 、 fetch 、 insert 、 open 、 select 、 update 前隐式执行一个 begin transaction 命令)


end





set transaction isolation level 1


-- 设置会话所用的事务隔离级别。当设置此选项后,所有当前或将来的事务都将在些隔离级别上运行


--level 1 的意义:允许对数据使用共享读取锁


select @low = @@minsuid, @high = @@maxsuid,


@spidlow = @@minspid, @spidhigh = @@maxspid


-- 给局部变量赋值,四个全局变量的含义:


--@@minsuid :最小服务器用户 ID


--@@maxsuid :最大服务器用户 ID


--@@minspid :最小服务器进程 ID


--@@maxspid :最大服务器进程 ID





if @loginame is not NULL


-- 判断存储过程的参数是否为空


begin


-- 开始一个新的批


select @low = suser_id(@loginame), @high = suser_id(@loginame)


--suser_id: 系统函数,返回服务器用户在 syslogins 表中的 ID 号





if @low is NULL


-- 如果参数 @loginame 不正确的话, suser_id 应该返回 NULL


begin


if @loginame like "[0-9]%"


-- 判断一下 @loginame 是不是数字开头的字符串


begin


-- 如果是的话把说明参数 @loginame 应该是服务器系统进和 ID


select @spidlow = convert(int, @loginame),


@spidhigh = convert(int, @loginame),


@low = 0, @high = @@maxsuid


-- 把参数 @loginame 转换成 int 型并赋给 @spidlow 和 @spidhigh


end


else


-- 如果不是数据开头的字符串,返回错误代码,并返回


begin


/*


** 17231, "No login with the specified name exists."


*/


raiserror 17231


-- 返回的错误号是 17231


--raiserror 的作用是返回预定义的错误号


return (1)


end


end


end


-- 以上进行的工作是将 @loginame 进行处理,生成下面查询语言的所需的条件值 @low 、 @high 、 @spidlow 、 @spidhigh


select @len1 = max(datalength(suser_name(suid))),


@len2 = max(datalength(db_name(dbid))),


@len3 = max(datalength(suser_name(origsuid)))


from master..sysprocesses


where suid >= @low and suid <= @high and


spid >= @spidlow and spid <= @spidhigh


--suser_name() :返回当前服务器用户的名称或已指定服务器用户 ID 的用户


--db_name() :返回已指定 ID 号的数据库的名称


--suser_name() :返回当前服务用户的名称或已指定服务器用户 ID 的用户





--datalength() :返回指定列或字符串的实际长度(以字节表示)


--max() :返回表达式的最大值





-- 以上语句找出 master 库 sysprocesses 表中 suid 、 dbid 、 origsuid 三列的最大实际长度





-- 以下语句是返回结果


-- 两个 select 语句的检索列、 from 、 where 、 order 子句都是一样的,只是检索列的字符串长度不一致!(更好看些,呵呵)


-- 两个 select 语句都是从 master 库 sysprocesses 表中检索出符合条件的指定列, 红色的地方是两个 select 不一致的地方 。


if (@len1 > 8 or @len2 > 6 or @len3 > 8)


begin


select fid,


spid,


status,


loginame=suser_name(suid),


origname=isnull(suser_name(origsuid), suser_name(suid)),


hostname,


blk_spid=convert(char(5),blocked),


dbname=db_name(dbid),


cmd,


block_xloid


from master..sysprocesses


where suid >= @low and suid <= @high


and spid >= @spidlow and spid <= @spidhigh


order by fid,spid,dbname


end


else


begin


select fid,


spid,


status,


loginame= convert(char(12), suser_name(suid) ) ,


origname= convert(char(12), isnull(suser_name(origsuid), suser_name(suid)) ) ,


hostname,


blk_spid=convert(char(5),blocked),


dbname=convert(char(10),db_name(dbid)),


cmd,


block_xloid


from master..sysprocesses


where suid >= @low and suid <= @high


and spid >= @spidlow and spid <= @spidhigh


order by fid,spid,dbname


end





return (0)


-- 返回


go





Grant Execute on dbo.sp_who to public


-- 向 public 组授予执行 sp_who 的权限


go


setuser


-- 如果在执行 setuser 命令时没有指定用户名,则将重新建立数据库所有者的初始标识


go





-- 我们可以看到,该存储过程的基本思路是先对传入的参数进行处理,生成查询用的条件参数,进而得出查询结果。


-- 对于该存储过程为了最终显示效果而加入的一段代码的作法,是值得我们学习的。







分析下来,如果你执行一个 sp_who '1sgfadf'

就会发生:

Syntax error during explicit conversion of VARCHAR value '1sgfadf' to a INT field.

的错误


呵呵,都是下面这段语句惹的祸:

if @loginame like "[0-9]%"


-- 判断一下 @loginame 是不是数字开头的字符串


begin


-- 如果是的话把说明参数 @loginame 应该是服务器系统进和 ID


select @spidlow = convert(int, @loginame),


@spidhigh = convert(int, @loginame),


@low = 0, @high = @@maxsuid


-- 把参数 @loginame 转换成 int 型并赋给 @spidlow 和 @spidhigh


end



网络虽虚拟,技术无边界,来看看大家“真面目”!
2007-9-27 18:431楼
[ 顶部 ]
 
ribut9225
主版主  点击可查看详细


开坛元老   内阁大臣   诚信兄弟   主版主专用   巨蟹座  
帖子 3065
精华 1
无忧币 5692
积分 4076
阅读权限 150
来自 (保密)
注册日期 2006-6-22
最后登录 2008-9-5 离线

[查看资料]  [发短消息]  [Blog
  QQ       
发表于:2007-9-28 15:36 
高手
学习了



用户必读,51CTO积分系统调整通知
2007-9-28 15:362楼
[ 顶部 ]
     
论坛跳转:  

| | |

| | |

标记已读 · 删除论坛Cookies · 文本版 · WAP
 
| 诚征版主 | 版主堂 | 意见建议 | 大史记 | 论坛地图
Copyright©2005-2008 51CTO.COM  Powered by Discuz!
本论坛言论纯属发布者个人意见,不代表51CTO网站立场!如有疑义,请与管理员联系。
京ICP备05051492号