我们在SQL Server 2000中使用了“未记录的”xp_fileexist存储过程多年,并且没有遇到任何问题。在2005年,如果执行的用户帐户不是系统管理员,它们似乎会略微修改行为以始终返回0。如果SQL Server服务在LocalSystem帐户下运行并且您尝试检查网络上的文件,它似乎也返回零。
我想摆脱xp_fileexist。有没有人有更好的方法从存储过程内部检查网络位置是否存在文件?
答案 0 :(得分:5)
您必须将CLR标记为EXTERNAL_ACCESS才能访问System.IO命名空间,但是事情并非如此。
SAFE是默认权限集,但它具有很高的限制性。使用SAFE设置,您只能访问本地数据库中的数据,以对该数据执行计算逻辑。 EXTERNAL_ACCESS是权限层次结构中的下一步。此设置允许您访问外部资源,例如文件系统,Windows事件查看器和Web服务。 SQL Server 2000及更早版本中无法进行此类资源访问。此权限集还限制了指针访问等操作,这些操作会影响程序集的健壮性。 UNSAFE权限集假定完全信任程序集,因此不会产生“代码访问安全性”限制。此设置与扩展存储过程功能的方式相当 - 您假设所有代码都是安全的。但是,此设置会限制为具有sysadmin权限的用户创建不安全的程序集。 Microsoft建议您尽可能避免创建不安全的程序集。
答案 1 :(得分:4)
也许您正在寻找CLR存储过程。当您需要以某种方式与系统交互时,通常会使用这些。
答案 2 :(得分:3)
我仍然相信CLR程序可能是最好的选择。所以,我接受了这个答案。但是,要么我不那么聪明,要么实施起来非常困难。我们的SQL Server服务在本地帐户下运行,因为根据Mircosoft的说法,这是使iSeries链接服务器从64位SQL Server 2005实例运行的唯一方法。当我们将SQL Server服务更改为使用域帐户运行时,xp_fileexist命令适用于位于网络上的文件。
我创建了这个CLR存储过程,并使用设置为External的权限级别构建它并签名:
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;
然后我从Visual Studio将CLR存储过程部署到我的目标数据库,并使用此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.我可能会稍后再试,但就目前而言,我将尝试走另一条路。如果有人有一些光线,那将非常感激。
答案 3 :(得分:0)
@Paul,该代码看起来应该有效。您是否尝试过在该方法中进行一些跟踪以确保Convert.ToString(fileName)
不是以某种方式躲过路径?