Tôi đang cố gắng giúp đỡ một người bạn cá nhân (hiện giờ cũng là khách hàng) với một vấn đề liên quan đến SQL CLR . Ông có một máy chủ SQL với một cơ sở dữ liệu có 3 hội đồng NET được nhúng trong đó. Anh ấy yêu cầu tôi giúp anh ta trích xuất các hội đồng từ bên trong cơ sở dữ liệu và lưu chúng dưới dạng tệp .dll trên đĩa. Điều này thậm chí có thể?Trích xuất một Hội đồng .NET từ SQL Server 2005
Trả lời
Có, điều này là có thể. Biểu diễn nhị phân thực tế của các assembly trực tiếp trong danh mục SQL cho máy chủ của bạn. Cụ thể là, nếu bạn điều hành một sự tham gia giữa sys.assembly_files và sys.assemblies, bạn có thể truy cập tất cả thông tin mà bạn cần . Tập hợp nhị phân nằm trong cột nội dung của khung nhìn sys.assembly_files .
Nhưng để trích xuất biểu diễn nhị phân từ SQL Server và thành tệp trên đĩa, bạn sẽ phải viết một số mã .NET cần chạy trên cơ sở dữ liệu tương tự tại nơi bạn đang tham chiếu. Trong Visual Studio bắt đầu một dự án CLR SQL và thêm một lớp học để nó với đoạn mã sau:
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();
}
}
}
}
}
Sau đó xây dựng dự án và triển khai nó đến cơ sở dữ liệu của bạn. Đảm bảo rằng tùy chọn cấu hình CLR Bật được bật trên Máy chủ SQL. Đây có lẽ là đã được bật, vì bạn có các hội đồng trên đó. Trong trường hợp thực hiện clr không kích hoạt bạn có thể chạy đoạn mã sau vào SSMS để kích hoạt nó:
sp_configure 'clr enabled', 1
go
reconfigure
go
Một điều nữa mà bạn cần phải nhận thức được là bởi SQL mặc định máy chủ có thể không cho phép bạn viết vào đĩa từ mã .NET. Nếu bạn gặp lỗi bảo mật FileIO khi bạn chạy mã ở trên bằng cách gọi thủ tục được lưu trữ trong SSMS, bạn sẽ cần phải định cấu hình bộ quyền thích hợp cho cụm . Bạn có thể thực hiện điều này thông qua SSMS: nhấp chuột phải vào hội đồng mới và xem Tập hợp quyền trong hộp thoại Thuộc tính. Đặt nó vào Truy cập bên ngoài. Bây giờ bạn sẽ có thể xuất lắp ráp của bạn bằng cách chạy đoạn mã sau trong SSMS:
exec SaveAssembly 'AssemblyName', 'f:\path\to\assemblyname.dll'
Hope làm việc này cho bạn ...
Yes.
làm một select * from sys.assembly_files
để tìm id của assembly mà bạn muốn
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
tuyệt vời. Đơn giản và sạch sẽ. Cảm ơn bạn. –
giải pháp Preet của làm việc cho tôi, nhưng tôi đã phải cấu hình Ole Tự động hóa để làm việc trên SQL Server 2008 R2. Cũng lưu ý rằng SaveToFile không hoạt động - nó cũng không cung cấp thông báo lỗi - trừ khi SQL Server có quyền đối với thư mục đó. Trong trường hợp của tôi, tôi đã sử dụng thư mục dữ liệu của cá thể SQL Server hoạt động tốt.
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
Cách tiếp cận Jonas cũng hoạt động tốt như ứng dụng Console hoặc tập lệnh Linqpad - không cần mã được thực thi cục bộ trong quá trình SQL, như ông ngụ ý.ví dụ như chiết xuất lắp ráp tSQLt (một công cụ kiểm tra) từ một cơ sở dữ liệu:
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");
}
}
}
}
Lấy Preet và Nate giải pháp và biến chúng thành một kịch bản mà sẽ xuất khẩu TẤT CẢ procs clr sử dụng một con trỏ:
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
tôi đã tìm thấy một giải pháp đơn giản cho vấn đề này, điều này là cần thiết vì sp_OACreate
dường như không có sẵn cho SQL Server 2017 (ít nhất, không phải là phiên bản Linux).
Bạn có thể chỉ cần sử dụng các tiện ích BCP để viết lắp ráp vào một tập tin trên đĩa, như vậy:
/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
Và sử dụng tập tin định dạng này (bcp.fmt):
13.0
1
1 SQLBINARY 0 0 "" 1 content ""
Các tập tin kết quả (/tmp/my_assembly.so) có thể được sử dụng trong việc tạo ra một hội đồng, như vậy:
CREATE ASSEMBLY [MyAssembly] AUTHORIZATION [dbo]
FROM '/tmp/my_assembly.so' WITH PERMISSION_SET = SAFE;
- 1. Trích xuất XAML từ một hội đồng .Net
- 2. Trích xuất giờ từ một DateTime (SQL Server 2005)
- 3. Lấy ngày của một hội đồng .NET
- 4. SQL Server 2005 Replication
- 5. Tải hội đồng WinRT từ .NET
- 6. Isoweek trong SQL Server 2005
- 7. Cách trích xuất Google Từ đồng nghĩa
- 8. Thời gian truy cậpZoneInfo từ SQL 2005 Server
- 9. Hội đồng .NET là gì?
- 10. Lỗi cắt ngắn nhập vào SQL Server 2005 từ Excel
- 11. Vấn đề với trích xuất ngày trong SQL Server
- 12. Chỉnh sửa các từ đồng nghĩa trong MS SQL Server 2005
- 13. Cách đánh dấu một hội đồng .net là an toàn?
- 14. Vấn đề chặn SQL Server 2005 (ASYNC_NETWORK_IO)
- 15. CHECKSUM() va chạm trong SQL Server 2005
- 16. Connect ray ứng dụng SQL Server 2005 từ Windows
- 17. Truy vấn Active Directory từ SQL Server 2005
- 18. SQL server 2005 mất chính xác số
- 19. Tôi có thể chạy mã từ một hội đồng .NET từ một dòng lệnh không?
- 20. Sql Server 2008 - Thả một từ đồng nghĩa
- 21. SQL Server 2005: Nullable Foreign Key Constraint
- 22. Số Ba Tư trong SQL Server 2005
- 23. Phân trang SQL Server 2005 Kết quả
- 24. Chính xác SQL Server 2005 là gì?
- 25. Xuất từ SQLite sang SQL Server
- 26. SQL Express 2005/2008 Connections đồng thời
- 27. Trích xuất từ đầu tiên của chuỗi trong truy vấn SQL Server
- 28. Nhiều lệnh trên cùng một dòng trong SQL Server 2005
- 29. Đổi tên một cột trong MS SQL Server 2005
- 30. Cách cập nhật trình phân giải xung đột khi nâng cấp từ SQL Server 2005 lên SQL-Server 2008
Cách tiếp cận này hoạt động tốt khi thực hiện ext ernally quá - bạn không cần phải đi theo con đường SQLCLR. Xem câu trả lời của tôi bên dưới – piers7