提问人:Paul G 提问时间:8/20/2008 最后编辑:MattPaul G 更新时间:11/26/2014 访问量:9753
检查 SQL Server 2005 存储过程中是否存在文件的最佳方法是什么?
What is the best method for checking if a file exists from a SQL Server 2005 stored procedure?
问:
我们在 SQL Server 2000 中使用了“未记录”的xp_fileexist存储过程多年,并且没有遇到任何问题。在 2005 年,他们似乎稍微修改了行为,如果执行用户帐户不是系统管理员,则始终返回 0。如果 SQL Server 服务在 LocalSystem 帐户下运行,并且您正在尝试检查网络上的文件,则它似乎也会返回零。
我想远离xp_fileexist。有没有人有更好的方法从存储过程内部检查网络位置是否存在文件?
答:
也许 CLR 存储过程就是您正在寻找的。当您需要以某种方式与系统交互时,通常会使用这些工具。
您必须将 CLR 标记为 EXTERNAL_ACCESS 才能访问 System.IO 命名空间,但随着事情的发展,这并不是一个坏方法。
SAFE 是默认权限集,但它具有高度限制性。使用 SAFE 设置,您只能访问本地数据库中的数据,以便对该数据执行计算逻辑。 EXTERNAL_ACCESS 是权限层次结构中的下一步。此设置允许您访问外部资源,例如文件系统、Windows 事件查看器和 Web 服务。在 SQL Server 2000 及更早版本中无法进行这种类型的资源访问。此权限集还限制影响程序集可靠性的操作,例如指针访问。 UNSAFE 权限集假定程序集完全信任,因此不会施加“代码访问安全性”限制。此设置与扩展存储过程的工作方式类似,即假定所有代码都是安全的。但是,此设置将创建不安全程序集限制为具有 sysadmin 权限的用户。Microsoft 建议您尽可能避免创建不安全的程序集。
我仍然认为 CLR 过程可能是最好的选择。所以,我接受这个答案。但是,要么我不是那么聪明,要么很难实现。我们的 SQL Server 服务在本地帐户下运行,因为根据 Mircosoft 的说法,这是让 iSeries 链接服务器从 64 位 SQL Server 2005 实例工作的唯一方法。当我们将 SQL Server 服务更改为使用域帐户运行时,xp_fileexist 命令适用于位于网络上的文件。
我创建了这个 CLR 存储过程,并在权限级别设置为“外部”的情况下构建了它,并对其进行了签名:
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Security.Principal;
public partial class StoredProcedures
{
[Microsoft.SqlServer.Server.SqlProcedure]
public static void FileExists(SqlString fileName, out SqlInt32 returnValue)
{
WindowsImpersonationContext originalContext = null;
try
{
WindowsIdentity callerIdentity = SqlContext.WindowsIdentity;
originalContext = callerIdentity.Impersonate();
if (System.IO.File.Exists(Convert.ToString(fileName)))
{
returnValue = 1;
}
else
{
returnValue = 0;
}
}
catch (Exception)
{
returnValue = -1;
}
finally
{
if (originalContext != null)
{
originalContext.Undo();
}
}
}
}
然后我运行了这些 TSQL 命令:
USE master
GO
CREATE ASYMMETRIC KEY FileUtilitiesKey FROM EXECUTABLE FILE = 'J:\FileUtilities.dll'
CREATE LOGIN CLRLogin FROM ASYMMETRIC KEY FileUtilitiesKey
GRANT EXTERNAL ACCESS ASSEMBLY TO CLRLogin
ALTER DATABASE database SET TRUSTWORTHY ON;
然后,我将 CLR 存储的 proc 从 Visual Studio 部署到我的目标数据库,并使用此 TSQL 从使用 Windows 身份验证登录的 SSMS 执行:
DECLARE @i INT
--EXEC FileExists '\\\\server\\share\\folder\\file.dat', @i OUT
EXEC FileExists 'j:\\file.dat', @i OUT
SELECT @i
无论我尝试本地文件还是网络文件,我总是得到 0。我以后可能会再试一次,但现在,我将尝试走一条不同的路。如果有人能有所启发,将不胜感激。
评论