频 道 直 达 - 新闻 - 培训 - 软件 - 教程 - 前沿 - 组网 - 系统应用 - 安全 - 编程 - 存储 - 操作系统 - 数据库 - 服务器 - 专题 - 产品 - 案例库 - 读书 - 博客 - BBS
51CTO.COM_中国最大的网络技术网站
找资料:

7.8 CLR存储过程(1)

作者: (美)Itzik Ben-gan... 赵立东译 出处:电子工业出版社博文视点  2007-10-27 13:04    砖    好    评论   进入论坛
阅读提示:《Microsoft SQL Server 2005技术内幕:T-SQL程序设计》第7章首先简要介绍SQL Server 2005所支持的不同类型的存储过程,然后再深入研究它的细节。本文讲的是CLR存储过程。

7.8  CLR存储过程

SQL Server 2005允许使用任意 .NET语言开发CLR存储过程(以及其他程序一样)。上一章介绍了一些关于CLR程序的基础知识,给出了在什么情况下用CLR程序代替T-SQL的建议,并描述了如何开发CLR程序。 附录A包含了开发、生成、部署和测试 .NET代码的操作指南。在这里,我将演示两个CLR存储过程的示例,它提供了T-SQL代码所不具备的功能。

第一个示例是一个名为usp_GetEnvInfo 的CLR存储过程。该存储过程收集环境变量中的信息并把它们以表格形式返回。该存储过程返回的环境变量包括:机器名称、处理器、OS版本、CLR版本。

为了收集环境变量中的信息,程序集需要对操作系统资源进行外部访问。创建程序集时(使用CREATE ASSEMBLY命令),默认使用限制最高的PERMISSION_SET选项SAFE,这意味它们被限制为只能访问数据库资源。这是推荐的选项,这样可以获取最大的安全性和稳定性。权限集选项EXTERNAL_ACCESS 和UNSAFE(在CREATE ASSEMBLY 或 ALTER ASSEMBLY命令指定,或者在Visual Studio 中工程 | 属性对话框上的数据库选项卡指定)允许对文件、网络、环境变量或注册表这样的系统资源进行外部访问。要允许EXTERNAL_ACCESS 和UNSAFE程序集运行,你需要把数据库选项TRUSTWORTHY设置为ON。允许EXTERNAL_ACCESS 或UNSAFE程序集运行会存在安全风险,应该避免这样做。稍后我将描述一个更为安全的解决方案,我先演示EXTERNAL_ACCESS选项。要把CLRUtilities数据库的TRUSTWORTHY选项设置为ON,并把CLRUtilities程序集的权限集改为EXTERNAL_ACCESS,运行下面的代码:

-- 使用EXTERNAL_ACCESS 权限集需要把数据库选项TRUSTWORTHY 设置为ON 
ALTER DATABASE CLRUtilities SET TRUSTWORTHY ON;
GO
-- 修改程序集PERMISSION_SET = EXTERNAL_ACCESS
ALTER ASSEMBLY CLRUtilities
WITH PERMISSION_SET = EXTERNAL_ACCESS;
这时你就可以运行usp_GetEnvInfo存储过程了。UNSAFE程序集拥有任意权限并会危及SQL Server的健壮性和系统的安全。EXTERNAL_ACCESS程序集拥有和SAFE程序集一样的可靠性和稳定性,但在安全方面它们类似于UNSAFE程序集。
一个更为安全的解决方案是用强名称密钥文件(strong-named key file)为程序集签名或使用证书为授权码(Authenticode)签名。强名称(或证书)是SQL Server内部创建的非对称秘钥(asymmetric key)(或证书),对应一个拥有EXTERNAL ACCESS ASSEMBLY权限(对于external access程序集) 或UNSAFE ASSEMBLY权限(对于unsafe程序集)的登录。例如,假设CLRUtilities程序集的代码需要用EXTERNAL_ ACCESS权限集运行。你可以在Visual Studio中工程|属性对话框上的签名选项卡中,使用强名称密钥文件为程序集签名。然后运行下面的代码从可执行的 .dll文件中创建非对称密钥,并创建一个拥有EXTERNAL_ACCESS ASSEMBLY权限的登录。

-- 从已签名的程序创建非对称密钥
-- 注意:必须使用强名称密钥文件为程序集签名USE master
GO
CREATE ASYMMETRIC KEY CLRUtilitiesKey
FROM EXECUTABLE FILE =
'C:\CLRUtilities\CLRUtilities\bin\Debug\CLRUtilities.dll'
-- 创建登录并授予其external access权限
CREATE LOGIN CLRUtilitiesLogin FROM ASYMMETRIC KEY CLRUtilitiesKey
GRANT EXTERNAL ACCESS ASSEMBLY TO CLRUtilitiesLogin
GO
关于程序集安全的更详细的信息,请参考联机丛书:http://msdn2.microsoft.com/en-us/ library/ms345106.aspx。
代码清单7-10显示了使用C# 代码编写的usp_GetEnvInfo存储过程的定义。

代码清单7-10  CLR usp_GetEnvInfo 存储过程,C#版

 // 以表格形式返回环境信息的存储过程
[SqlProcedure]
public static void usp_GetEnvInfo()
{
// 创建一个record- 表示行的对象
// 包括SQL表的元数据
SqlDataRecord record = new SqlDataRecord(
new SqlMetaData("EnvProperty", SqlDbType.NVarChar, 20),
new SqlMetaData("Value", SqlDbType.NVarChar, 256));
// 标记要发送回客户端的结果集的开始
// record参数用于构造结果集的元数据
//
SqlContext.Pipe.SendResultsStart(record);
// 填充一些行并通过管道发送它们
record.SetSqlString(0, @"Machine Name");
record.SetSqlString(1, Environment.MachineName);
SqlContext.Pipe.SendResultsRow(record);
record.SetSqlString(0, @"Processors");
record.SetSqlString(1, Environment.ProcessorCount.ToString());
SqlContext.Pipe.SendResultsRow(record);
record.SetSqlString(0, @"OS Version");
record.SetSqlString(1, Environment.OSVersion.ToString());
SqlContext.Pipe.SendResultsRow(record);
record.SetSqlString(0, @"CLR Version");
record.SetSqlString(1, Environment.Version.ToString());
SqlContext.Pipe.SendResultsRow(record);
//标记结果集的结尾
SqlContext.Pipe.SendResultsEnd();
}

在这个存储过程,你可以看到在SQL Server CLR程序中使用了一些特殊的ADO.NET扩展。它们定义在 .NET2.0的Microsoft.SqlServer.Server命名空间下。

当你从SQL Server调用存储过程时,已经建立了连接。不必再打开一个新的连接;你需要从服务器上运行的代码中访问调用者的上下文。调用者的上下文是由SqlContext对象提供的。在使用SqlContext对象之前,应该先使用IsAvailable属性测试它是否可用。

该存储过程从操作系统中获取一些运行环境的数据。这些数据可以通过Environment对象的属性获取,该对象位于System命名空间。但是你获取的数据是文本格式的。在这个CLR存储过程中,你会看到如何生成任意格式的行集。程序的代码把数据保存在SqlDataRecord对象中,它表示的一个数据行,并通过SqlMetaData对象为该行定义架构。
T-SQL存储过程使用SELECT语句把结果发送到调用者的“管道(pipe)”。这是把结果发送给调用者的最有效的方式。在SQL Server中运行的CLR程序也公开了同样的方法。SqlPipe对象的send方法可以把结果发送给连接的管道。使用SqlContext对象的Pipe属性可以得到实例化的SqlPipe对象。

代码清单7-11显示了使用Visual Basic代码编写的usp_GetEnvInfo存储过程的定义。

代码清单7-11  CLR usp_GetEnvInfo存储过程,Visual Basic版

 '以表格形式返回环境信息的存储过程
<SqlProcedure()> _
Public Shared Sub usp_GetEnvInfo()
'创建一个record- 表示行的对象
'包括SQL表的元数据
Dim record As New SqlDataRecord(_
New SqlMetaData("EnvProperty", SqlDbType.NVarChar, 20), _
New SqlMetaData("Value", SqlDbType.NVarChar, 256))
'标记要发送回客户端的结果集的开始
' record参数用于构造结果集的元数据
'
SqlContext.Pipe.SendResultsStart(record)
''填充一些行并通过管道发送它们
record.SetSqlString(0, "Machine Name")
record.SetSqlString(1, Environment.MachineName)
SqlContext.Pipe.SendResultsRow(record)
record.SetSqlString(0, "Processors")
record.SetSqlString(1, Environment.ProcessorCount.ToString())
SqlContext.Pipe.SendResultsRow(record)
record.SetSqlString(0, "OS Version")
record.SetSqlString(1, Environment.OSVersion.ToString())
SqlContext.Pipe.SendResultsRow(record)
record.SetSqlString(0, "CLR Version")
record.SetSqlString(1, Environment.Version.ToString())
SqlContext.Pipe.SendResultsRow(record)
'标记结果集的结尾
SqlContext.Pipe.SendResultsEnd()
End Sub
运行下面的代码在CLRUtilities数据库中注册C# 版的usp_GetEnvInfo存储过程。
USE CLRUtilities;
GO
IF OBJECT_ID('dbo.usp_GetEnvInfo') IS NOT NULL
DROP PROC usp_GetEnvInfo;
GO
CREATE PROCEDURE dbo.usp_GetEnvInfo
AS EXTERNAL NAME CLRUtilities.CLRUtilities.usp_GetEnvInfo;


如果你是用Visual Basic开发的,用下面的代码注册该存储过程。

CREATE PROCEDURE dbo.usp_GetEnvInfo
AS EXTERNAL NAME
CLRUtilities.[CLRUtilities.CLRUtilities].usp_GetEnvInfo;
运行下面的代码测试usp_GetEnvInfo存储过程,产生的输出如表7-15所示。

EXEC dbo.usp_GetEnvInfo;

表7-15  usp_GetEnvInfo存储过程的输出

EnvProperty

Value

Machine Name

DOJO

Processors

1

OS Version

Microsoft Windows

NT 5.1.2600 Service Pack 2

CLR Version

2.0.50727.42


CLR存储过程的第二个示例是usp_GetAssemblyInfo存储过程,它返回与输入程序集相关的信息。

代码清单7-12显示了C# 版的usp_GetAssemblyInfo存储过程的定义。

代码清单7-12  CLR usp_GetAssemblyInfo存储过程,C#版

// 返回程序集信息的存储过程
// 使用反射
[SqlProcedure]
public static void usp_GetAssemblyInfo(SqlString asmName)
{
// 获取程序集的clr 名称
String clrName = null;
// 获取上下文
using (SqlConnection connection =
new SqlConnection("Context connection = true"))
{
connection.Open();
using (SqlCommand command = new SqlCommand())
{
//得到程序集并加载它
command.Connection = connection;
command.CommandText =
"SELECT clr_name FROM sys.assemblies WHERE name = @asmName";
command.Parameters.Add("@asmName", SqlDbType.NVarChar);
command.Parameters[0].Value = asmName;
clrName = (String)command.ExecuteScalar();
if (clrName == null)
{
throw new ArgumentException("Invalid assembly name!");
}
Assembly myAsm = Assembly.Load(clrName);
// 创建一个 record – 表示行的对象
// 包含SQL表的元数据
SqlDataRecord record = new SqlDataRecord(
new SqlMetaData("Type", SqlDbType.NVarChar, 50),
new SqlMetaData("Name", SqlDbType.NVarChar, 256));
//标记要发送回客户端的结果集的开始

   //record参数用于构造结果集的元数据

SqlContext.Pipe.SendResultsStart(record);
// 得到程序集中的所有类型
Type[] typesArr = myAsm.GetTypes();
foreach (Type t in typesArr)
{
// SQL数据库中的类型应该是一个类或一个结构
if (t.IsClass == true)
{
record.SetSqlString(0, @"Class");
}
else
{
record.SetSqlString(0, @"Structure");
}
record.SetSqlString(1, t.FullName);
SqlContext.Pipe.SendResultsRow(record);
// 找出所有公共的静态方法
MethodInfo[] miArr = t.GetMethods();
foreach (MethodInfo mi in miArr)
{
if (mi.IsPublic && mi.IsStatic)
{
record.SetSqlString(0, @" Method");
record.SetSqlString(1, mi.Name);
SqlContext.Pipe.SendResultsRow(record);
}
}
}
// 标记结果集的结尾
SqlContext.Pipe.SendResultsEnd();
}
}
}

【责任编辑:雪花 TEL:(010)68476606】

回书目   上一节   下一节
· 7.5 Execute As(10/27)
· 7.3 解析(10/23)
· 7.3 解析(10/23)
· 7.3 解析(10/23)
专题
存储为核心的系统发展之路
虚拟存储企业级应用座谈会
网络存储导论
SAN存储技术
网络存储入门——光纤通道
我也说两句

匿名发表

(如果看不清请点击图片进行更换)


中 国 最 大 的 网 络 技 术 网 站 ·
技 术 成 就 梦 想
订阅技术快讯
电子杂志下载
名称:SQL Server数据库管理精品黄皮书
简介:书中文章经过精挑细选,便于用户能根据自己的实际工作和学习,快速在本书寻找到相关资料。内容涵盖了SQL Server的安装与升级、语句查询、数据备份和恢复、自动化任务、数据同步、数据字典、安全和预防、性能和优化、集群等各方面应用信息,以及DBA管理人员在数据库管理工作中
名称:2007路由技术大全
简介:《2007路由技术大全》由51CTO.com网站特别策划制作,该书包括路由器技术、路由器产品、路由器配置、安全设置、路由器故障处理、路由器密码恢复,以及广大网友在实践使用中的心得经验和技巧文章,内容注重实用性,适用于初学者入门,也适合多年从业者提高,是一本实践和理论完
名称:网络安全精品应用黄皮书
简介:《2007精品网络安全黄皮书》包括了9个大类24个小类, 800余篇文章,内容包含了熊猫烧香病毒、DDOS攻击、ARP病等热点问题的介绍及解决方案。从病毒查杀、防范、系统、数据等各方面的安全设置到黑客技术的了解、防范,涉及到了安全应用的全部领域, 由浅至深内容全面。
浏览器的战国时代
浏览器的战国时代
ARP攻击防范与解决方案
ARP攻击防范与解决方案
NAC安全访问控制
NAC安全访问控制
· NAC安全访问控制
· 网络布线测试仪器
· Windows Server 2008专..
· Windows远程桌面应用
· 网络故障排除宝典
· 运营商封堵ADSL共享 中..
· 解析35岁技术人的价值..
· 世纪枭雄比尔盖茨的王..
· 主流品牌防火墙配置
· ASP.NET开发教程
· 超级计算机TOP500专题
· Vista SP1对决XP SP3
· SQL Server 2008/2005..
· 程序员如何成长?
· C#技术开发指南
· 虚拟化技术还有点“虚”
ARP攻击防范与解决方案
ARP攻击防范与解决方案
SQL Server 2008/2005全解
SQL Server 2008/2005全解
SOA 面向服务架构
SOA 面向服务架构
· SOA 面向服务架构
· SQL Server 2008/2005..
· Apache技术专题
· 三层交换技术专题
· SQL Server入门到精通
· Windows远程桌面应用
· C#技术开发指南
· Apache技术专题
· Windows集群服务应用
· C#技术开发指南
· 国际文档格式标准开战
· 路由器设置与口令恢复
· Linux 集群技术专题
· PHP开发应用手册
· SOA 面向服务架构
· 企业数据恢复指南
ARP攻击防范与解决方案
ARP攻击防范与解决方案
SQL Server 2008/2005全解
SQL Server 2008/2005全解
SQL Server入门到精通
SQL Server入门到精通
· SQL Server入门到精通
· SQL Server 2008/2005..
· SOA 面向服务架构
· Apache技术专题
· C#技术开发指南
· 三层交换技术专题
· Apache技术专题
· C#技术开发指南
· Windows远程桌面应用
· 企业数据恢复指南
· Windows集群服务应用
· 路由器设置与口令恢复
· Linux 集群技术专题
· SOA 面向服务架构
· 了解统一威胁管理(UTM)..
· 反垃圾邮件技术应用