Извлечение a.NET сборка из SQL Server 2005
Я пытаюсь помочь личному другу (который теперь также является клиентом) с SQL CLR смежная проблема. У него есть SQL Server с базой данных, которая имеет 3 сборки .NET встраивается в него. Он попросил меня помочь ему извлечь сборки из базы данных и сохранить их как .dll файлы на диске. Это вообще возможно?
7 ответов
Да, это возможно. Фактическое двоичное представление сборок live в каталоге SQL для вашего сервера. А именно, если вы выполните соединения между системный.assembly_files и sys.сборки вы можете получить всю информацию, которую вы необходимость. Двоичный файл сборок находится в столбце содержимое системы.файл сборки вид.
но для извлечения двоичного представления из 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 На сервере SQL включен параметр конфигурации Enabled. Это, вероятно, уже включено, так как у вас есть сборки на нем. В случае, если выполнение clr не включено вы можете запустить следующий код на SSMS, чтобы включить это:
sp_configure 'clr enabled', 1
go
reconfigure
go
еще одна вещь, о которой вам нужно знать, - это SQL server по умолчанию не позволяет записывать на диск из кода .NET. Если вы получите FileIO ошибка безопасности при запуске кода выше, вызвав хранимую процедуру в SSMS, вам нужно будет настроить правильный набор разрешений для собрание. Вы можете сделать это через SSMS: щелкните правой кнопкой мыши новую сборку и посмотрите набор разрешений в диалоговом окне Свойства. Установите его на внешний доступ. Теперь ты должно быть возможность экспорта сборок с помощью следующего кода в SSMS:
exec SaveAssembly 'AssemblyName', 'f:\path\to\assemblyname.dll'
надеюсь, это сработает для вас...
да.
сделать 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
подход Джонаса отлично работает как консольное приложение или скрипт 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");
}
}
}
}
решение Preet работало для меня, но мне пришлось настроить 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
Я нашел более простое решение этой проблемы, которое было необходимо, потому что 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;
принимая решения Preet и Nate и превращая их в скрипт, который будет экспортировать все процессы clr с помощью курсора:
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
альтернативным решением без кодирования является проект базы данных VisualStudio. создать новый проект базы данных и импортируйте свою базу данных со сборкой. Вы получите сценарии DDL вместе со сборками.
Примечание, вам нужно будет установить SSDT для Visual Studio.