Извлечение сборки .NET из SQL Server 2005 - PullRequest
16 голосов
/ 05 ноября 2010

Я пытаюсь помочь личному другу (который теперь также является клиентом) с SQL CLR связанная проблема. У него есть SQL Server с базой данных, которая имеет 3 сборки .NET впутался в это. Он попросил меня помочь ему извлечь сборки из базы данных и сохранить их как файлы .dll на диске. Это вообще возможно?

Ответы [ 7 ]

13 голосов
/ 05 ноября 2010

Да, это возможно.Фактическое двоичное представление сборок находится в каталоге SQL для вашего сервера.А именно, если вы запустите соединение между sys.assembly_files и sys.assemblies, вы сможете получить всю необходимую вам информацию.Двоичный файл сборок находится в столбце содержимого представления sys.assembly_files.

Но чтобы извлечь двоичное представление из SQL Server в файл на диске, вам нужно написать некоторый код .NET, который должен выполняться в той же базе данных, где сейчас находятся сборки, на которые вы ссылаетесь.В Visual Studio запустите проект SQL CLR и добавьте в него класс со следующим кодом:

using System;
using System.IO;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Security.Permissions;

namespace ExtractSqlAssembly {
    [PermissionSet(SecurityAction.Demand, Unrestricted = true, Name = "FullTrust")]
    public partial class SaveSqlAssembly {

        [SqlProcedure]
        public static void SaveAssembly(string assemblyName, string path) {
            string sql = @"SELECT AF.content FROM sys.assembly_files AF JOIN sys.assemblies A ON AF.assembly_id = A.assembly_id where AF.file_id = 1 AND A.name = @assemblyname";
            using (SqlConnection conn = new SqlConnection("context connection=true")) {
                using (SqlCommand cmd = new SqlCommand(sql, conn)) {
                    SqlParameter param = new SqlParameter("@assemblyname", SqlDbType.VarChar);
                    param.Value = assemblyName;
                    cmd.Parameters.Add(param);

                    cmd.Connection.Open();  // Read in the assembly byte stream
                    SqlDataReader reader = cmd.ExecuteReader();
                    reader.Read();
                    SqlBytes bytes = reader.GetSqlBytes(0);

                    // write the byte stream out to disk
                    FileStream bytestream = new FileStream(path, FileMode.CreateNew);
                    bytestream.Write(bytes.Value, 0, (int)bytes.Length);
                    bytestream.Close();
                }
            }
        }
    }
}

Затем соберите проект и разверните его в своей базе данных.Убедитесь, что опция конфигурации CLR Enabled включена на SQL Server.Это, вероятно, уже включено, так как у вас есть сборки на нем.В случае, если выполнение clr не включено, вы можете запустить следующий код в SSMS, чтобы включить его:

sp_configure 'clr enabled', 1
go

reconfigure
go

Еще одна вещь, о которой вам нужно знать, это то, что по умолчанию SQL-сервер может не разрешать записьна диск из .NET кода.Если вы получили ошибку безопасности FileIO при запуске приведенного выше кода при вызове хранимой процедуры в SSMS, вам потребуется настроить правильный набор разрешений для сборки.Вы можете сделать это через SSMS: щелкните правой кнопкой мыши новую сборку и посмотрите на Набор разрешений в диалоговом окне Свойства.Установите его на внешний доступ.Теперь вы сможете экспортировать сборки, запустив следующий код в SSMS:

exec SaveAssembly 'AssemblyName', 'f:\path\to\assemblyname.dll'

Надеюсь, это работает для вас ...

10 голосов
/ 05 ноября 2010

Да.

выполните select * from sys.assembly_files, чтобы найти идентификатор нужной сборки

DECLARE @IMG_PATH VARBINARY(MAX)
DECLARE @ObjectToken INT

SELECT @IMG_PATH = content FROM sys.assembly_files WHERE assembly_id = 65536

EXEC sp_OACreate 'ADODB.Stream', @ObjectToken OUTPUT
        EXEC sp_OASetProperty @ObjectToken, 'Type', 1
        EXEC sp_OAMethod @ObjectToken, 'Open'
        EXEC sp_OAMethod @ObjectToken, 'Write', NULL, @IMG_PATH
        EXEC sp_OAMethod @ObjectToken, 'SaveToFile', NULL, 'c:\temp\myassembly.dll', 2
        EXEC sp_OAMethod @ObjectToken, 'Close'
        EXEC sp_OADestroy @ObjectToken
6 голосов
/ 31 мая 2013

Подход Jonas также отлично работает как консольное приложение или сценарий Linqpad - нет необходимости в том, чтобы код выполнялся локально в процессе SQL, как он и подразумевает. например, извлечение сборки tSQLt (инструмент тестирования) из базы данных:

void Main()
{
    var assemblyName = "tSQLtCLR";
    var serverName = "localhost";
    var databaseName = "MyDb";
    var targetDir = Environment.ExpandEnvironmentVariables("%TEMP%");
    var targetFile = Path.Combine(targetDir, assemblyName) + ".dll";

    var sql = @"SELECT AF.content FROM sys.assembly_files AF JOIN sys.assemblies A ON AF.assembly_id = A.assembly_id where AF.file_id = 1 AND A.name = @assemblyName";

    var connectionString = string.Format("Data Source={0};Initial Catalog={1};Integrated Security=true", serverName, databaseName);
    using(var connection = new System.Data.SqlClient.SqlConnection(connectionString)){
        connection.Open();

        var command = connection.CreateCommand();
        command.CommandText = sql;
        command.Parameters.Add("@assemblyName", assemblyName);

        using(var reader = command.ExecuteReader()){
            if(reader.Read()){
                var bytes = reader.GetSqlBytes(0);

                File.WriteAllBytes(targetFile, bytes.Value);
                Console.WriteLine(targetFile);
            }else{
                throw new Exception("No rows returned");
            }
        }
    }
}
3 голосов
/ 30 марта 2011

Решение Преета мне помогло, но мне пришлось настроить Ole Automation для работы на SQL Server 2008 R2. Также обратите внимание, что SaveToFile не работает - и при этом не выдает сообщение об ошибке - если только у SQL Server нет разрешений на этот каталог. В моем случае я использовал папку данных экземпляра SQL Server, которая работала нормально.

EXECUTE SP_CONFIGURE 'show advanced options', 1
RECONFIGURE WITH OVERRIDE
GO

EXEC sp_configure 'Ole Automation Procedures', 1;
RECONFIGURE WITH OVERRIDE
GO

DECLARE @IMG_PATH VARBINARY(MAX)
DECLARE @ObjectToken INT

SELECT @IMG_PATH = content FROM sys.assembly_files WHERE assembly_id = 65546

EXEC sp_OACreate 'ADODB.Stream', @ObjectToken OUTPUT
        EXEC sp_OASetProperty @ObjectToken, 'Type', 1
        EXEC sp_OAMethod @ObjectToken, 'Open'
        EXEC sp_OAMethod @ObjectToken, 'Write', NULL, @IMG_PATH
        EXEC sp_OAMethod @ObjectToken, 'SaveToFile', NULL, 'C:\Program Files\Microsoft SQL Server\MSSQL10_50.MSSQLSERVER\MSSQL\DATA\myassembly.dll', 2
        EXEC sp_OAMethod @ObjectToken, 'Close'
        EXEC sp_OADestroy @ObjectToken  

EXEC sp_configure 'Ole Automation Procedures', 0;
RECONFIGURE WITH OVERRIDE
GO

EXECUTE SP_CONFIGURE 'show advanced options', 0
RECONFIGURE WITH OVERRIDE
GO
1 голос
/ 08 января 2018

Я нашел более простое решение этой проблемы, которое было необходимо, поскольку sp_OACreate, по-видимому, недоступно для SQL Server 2017 (по крайней мере, не для версии Linux).

Вы можете просто использовать утилиту BCP для записи сборки в файл на диске, например:

/opt/mssql-tools/bin/bcp "SELECT content FROM sys.assembly_files WHERE name = '${ASSEMBLY_NAME}'" \
    queryout /tmp/my_assembly.so -f bcp.fmt \
    -S localhost -U sa -P "${SA_PASSWORD}" -d master

И использовать этот формат файла (bcp.fmt):

13.0
1
1       SQLBINARY           0       0       ""   1     content                          ""

Полученный файл (/tmp/my_assembly.so) можно использовать при создании сборки, например:

CREATE ASSEMBLY [MyAssembly] AUTHORIZATION [dbo]
FROM '/tmp/my_assembly.so' WITH PERMISSION_SET = SAFE;
0 голосов
/ 11 июля 2018

Альтернативным решением без какого-либо кодирования является проект базы данных VisualStudio. Создайте новый проект базы данных и импортируйте базу данных со сборкой. Вы получите DDL-скрипты вместе со сборками.

Обратите внимание, вам нужно установить SSDT для Visual Studio .

0 голосов
/ 02 октября 2017

Взяв решения Преета и Нейта и превратив их в скрипт, который будет экспортировать ВСЕ процедуры с помощью курсора:

EXECUTE SP_CONFIGURE 'show advanced options', 1
RECONFIGURE WITH OVERRIDE
GO

EXEC sp_configure 'Ole Automation Procedures', 1;
RECONFIGURE WITH OVERRIDE
GO

RAISERROR ('Starting...', 0, 1) WITH NOWAIT

DECLARE @ObjectToken INT
DECLARE @AssemblyLocation VARCHAR(MAX)
DECLARE @Msg VARCHAR(MAX)
DECLARE @Content VARBINARY(MAX)
DECLARE @Count AS INT = (SELECT COUNT(name) FROM sys.assembly_files)

DECLARE AssemblyFiles CURSOR FAST_FORWARD
FOR
  SELECT 
    CAST(ROW_NUMBER() OVER (ORDER BY name) AS VARCHAR(10)) + ' of ' + CAST(@Count AS VARCHAR(10)) + ' - ' + name AS Msg,
    '[a location the server can write to]' + name + '.dll' AS AssemblyLocation,
    content    
  FROM
    sys.assembly_files
  ORDER BY 
    name

OPEN AssemblyFiles
FETCH NEXT FROM AssemblyFiles
INTO @Msg, @AssemblyLocation, @Content

WHILE @@FETCH_STATUS = 0
  BEGIN
    EXEC sp_OACreate 'ADODB.Stream', @ObjectToken OUTPUT
    EXEC sp_OASetProperty @ObjectToken, 'Type', 1
    EXEC sp_OAMethod @ObjectToken, 'Open'
    EXEC sp_OAMethod @ObjectToken, 'Write', NULL, @Content
    EXEC sp_OAMethod @ObjectToken, 'SaveToFile', NULL, @AssemblyLocation, 2
    EXEC sp_OAMethod @ObjectToken, 'Close'
    EXEC sp_OADestroy @ObjectToken  

    RAISERROR (@Msg, 0, 1) WITH NOWAIT

    FETCH NEXT FROM AssemblyFiles
    INTO @Msg, @AssemblyLocation, @Content
  END

CLOSE AssemblyFiles
DEALLOCATE AssemblyFiles

RAISERROR ('Done', 0, 1) WITH NOWAIT

EXEC sp_configure 'Ole Automation Procedures', 0;
RECONFIGURE WITH OVERRIDE
GO

EXECUTE SP_CONFIGURE 'show advanced options', 0
RECONFIGURE WITH OVERRIDE
GO
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...