SQL Server 2005 ストアド プロシージャからファイルが存在するかどうかを確認するための最良の方法は何ですか?
-
08-06-2019 - |
質問
私たちは SQL Server 2000 で「文書化されていない」xp_fileexist ストアド プロシージャを長年使用していましたが、問題はありませんでした。2005 年には、実行ユーザー アカウントが sysadmin ではない場合に常に 0 を返すように動作をわずかに変更したようです。SQL Server サービスが LocalSystem アカウントで実行されており、ネットワーク上のファイルをチェックしようとしている場合にも、ゼロが返されるようです。
xp_fileexist から離れたいです。ストアド プロシージャ内からネットワーク上の場所にファイルが存在するかどうかを確認するより良い方法がある人はいますか?
解決
CLR ストアド プロシージャが探しているものかもしれません。これらは通常、何らかの方法でシステムと対話する必要がある場合に使用されます。
他のヒント
System.IO 名前空間にアクセスするには、CLR を EXTERNAL_ACCESS としてマークする必要がありますが、状況としては、これは悪い方法ではありません。
SAFE はデフォルトの権限セットですが、非常に制限されています。SAFE 設定を使用すると、ローカル データベースのデータにのみアクセスして、そのデータに対して計算ロジックを実行できます。EXTERNAL_ACCESS は、権限階層の次のステップです。この設定により、ファイル システム、Windows イベント ビューア、Web サービスなどの外部リソースにアクセスできるようになります。このタイプのリソース アクセスは、SQL Server 2000 以前では不可能です。この権限セットは、アセンブリの堅牢性に影響を与えるポインター アクセスなどの操作も制限します。UNSAFE アクセス許可セットはアセンブリの完全な信頼を前提としているため、「コード アクセス セキュリティ」制限は課されません。この設定は、すべてのコードが安全であると想定する拡張ストアド プロシージャの機能に似ています。ただし、この設定では、安全でないアセンブリの作成が sysadmin 権限を持つユーザーに制限されます。Microsoft では、安全でないアセンブリの作成を可能な限り回避することをお勧めします。
私は今でも CLR 手順が最善の策であると信じています。したがって、その回答を受け入れます。しかし、私はそこまで頭が良くないか、実行するのが非常に難しいかのどちらかです。Microsoft の SQL Server サービスはローカル アカウントで実行されています。これは、Mircosoft によれば、それが 64 ビット SQL Server 2005 インスタンスから iSeries リンク サーバーを動作させる唯一の方法であるためです。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 ストアド プロシージャを 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 が返されます。後でまた挑戦するかもしれませんが、今のところは別の道を進んでみるつもりです。どなたか光を当てていただければ幸いです。
@Paul、そのコードは機能するようです。確認するためにそのメソッドにトレースを入れてみましたか Convert.ToString(fileName)
何とか道を整えていないでしょうか?