检查SQL Server 2005存储过程中是否存在文件的最佳方法是什么?

时间:2008-08-19 18:01:44

标签: sql-server sql-server-2005

我们在SQL Server 2000中使用了“未记录的”xp_fileexist存储过程多年,并且没有遇到任何问题。在2005年,如果执行的用户帐户不是系统管理员,它们似乎会略微修改行为以始终返回0。如果SQL Server服务在LocalSystem帐户下运行并且您尝试检查网络上的文件,它似乎也返回零。

我想摆脱xp_fileexist。有没有人有更好的方法从存储过程内部检查网络位置是否存在文件?

4 个答案:

答案 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)不是以某种方式躲过路径?