Каков наилучший способ проверки существования файла из хранимой процедуры SQL Server 2005?

StackOverflow https://stackoverflow.com/questions/16634

  •  08-06-2019
  •  | 
  •  

Вопрос

Мы использовали «недокументированную» хранимую процедуру xp_fileexist в течение многих лет в SQL Server 2000 и не имели с ней проблем.Кажется, в 2005 году они немного изменили поведение, чтобы всегда возвращать 0, если исполняющая учетная запись пользователя не является системным администратором.Также кажется, что он возвращает ноль, если служба SQL Server работает под учетной записью LocalSystem, и вы пытаетесь проверить файл в сети.

Я бы хотел уйти от xp_fileexist.Есть ли у кого-нибудь лучший способ проверить наличие файла в сетевом расположении изнутри хранимой процедуры?

Это было полезно?

Решение

Возможно, вам нужна хранимая процедура CLR.Обычно они используются, когда вам нужно каким-либо образом взаимодействовать с системой.

Другие советы

Вам придется пометить CLR как EXTERNAL_ACCESS, чтобы получить доступ к пространству имен System.IO, однако в сложившейся ситуации это неплохой способ сделать это.

SAFE — это набор разрешений по умолчанию, но он очень ограничительный.С настройкой SAFE вы можете получить доступ только к данным из локальной базы данных для выполнения вычислительной логики над этими данными.EXTERNAL_ACCESS — следующий шаг в иерархии разрешений.Этот параметр позволяет получить доступ к внешним ресурсам, таким как файловая система, средство просмотра событий Windows и веб-службы.Этот тип доступа к ресурсам невозможен в SQL Server 2000 и более ранних версиях.Этот набор разрешений также ограничивает такие операции, как доступ к указателю, которые влияют на надежность сборки.Набор разрешений UNSAFE предполагает полное доверие к сборке и, следовательно, не накладывает ограничений «Безопасность доступа к коду».Этот параметр аналогичен тому, как функционируют расширенные хранимые процедуры — вы предполагаете, что весь код безопасен.Однако этот параметр ограничивает создание небезопасных сборок пользователями, имеющими права системного администратора.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 в своей целевой базе данных из Visual Studio и использовал этот TSQL для выполнения из SSMS, вошедшей в систему с аутентификацией Windows:

DECLARE @i INT
--EXEC FileExists '\\\\server\\share\\folder\\file.dat', @i OUT
EXEC FileExists 'j:\\file.dat', @i OUT
SELECT @i

Пробую ли я локальный файл или сетевой файл, я всегда получаю 0.Возможно, позже я попробую еще раз, но сейчас я попробую пойти другим путем.Если у кого-то есть что пролить свет, мы будем очень признательны.

@Пол, этот код выглядит так, будто он должен работать.Пробовали ли вы добавить трассировку в этот метод, чтобы убедиться Convert.ToString(fileName) путь не промывает каким-то образом?

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top