我正在嘗試幫助一個私人朋友(他現在也是一個客戶端)與SQL CLR 相關的問題。他有一個SQL Server,其中嵌入了3個.NET程序集 。他讓我幫他從 數據庫中提取組件,並將它們保存爲磁盤上的.dll文件。這甚至有可能嗎?從SQL Server 2005中提取.NET程序集
回答
是的,這是可能的。組件的實際二進制表示在您的服務器的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();
}
}
}
}
}
然後生成該項目並將其部署到你的數據庫。確保在SQL Server上啓用了CLR 啓用配置選項。這可能是 已經啓用,因爲你有它的組件。如果CLR執行力不 使您可以運行在SSMS下面的代碼,使之:
sp_configure 'clr enabled', 1
go
reconfigure
go
,你需要知道的一件事是在默認情況下,SQL Server可能 不允許你寫從.NET代碼到磁盤。如果通過調用 SSMS中的存儲過程來運行上述代碼時出現FileIO 安全錯誤,則需要爲 程序集配置正確的權限集。您可以通過SSMS執行此操作:右鍵單擊新的程序集,然後在「屬性」對話框中查看權限集 。將其設置爲外部訪問。現在你 應該能夠運行在SSMS下面的代碼導出組件:
exec SaveAssembly 'AssemblyName', 'f:\path\to\assemblyname.dll'
希望這對你的作品...
是。
做select * from sys.assembly_files
找到組件的ID你想
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
真棒。簡單而乾淨。謝謝。 – 2013-04-24 23:19:43
普里特的解決方案爲我,但我不得不配置OLE自動化到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
喬納斯辦法正常工作的控制檯應用程序或腳本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");
}
}
}
}
以普里特和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
我找到了一個更簡單的解決方案來解決這個問題,這很有必要,因爲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;
- 1. 從SQL Server 2005 Reporting Services報告調用.Net程序集?
- 2. 從SQL Server 2005中提取表權限
- 3. 在SQL Server 2005中使用.net程序集
- 4. SQL Server Management Studio集成到Sql Server 2005 Enterprise安裝程序中?
- 5. 備份後從SQL Server數據庫中提取程序集
- 6. 提取SQL SERVER 2005中的字符?
- 7. SQL Server 2005從C#流創建程序集#
- 8. SQL Server 2005和.NET查詢
- 9. 獲取在SQL Server 2005中
- 10. CLR程序集將不會加載到64位SQL Server 2005中
- 11. 使用c從SQL Server 2005中提取數據#
- 12. 試圖在.NET中從SQL Server中提取圖像,獲取UnauthorizedAccessException
- 13. 如何從SQL Server 2005中的存儲過程中提取參數?
- 14. 從.NET程序集中獲取ProgID
- 15. 從.Net程序集中抓取XAML
- 16. SQL Server 2005中
- 17. SQL Server 2005中
- 18. SQL Server 2005中的字符集
- 19. 升級從SQL Server 2005到SQL Server 2008
- 20. 從SQL Server 2000遷移到SQL Server 2005
- 21. 從SQL Server 2005升級到SQL Server 2008
- 22. .net Windows應用程序使用SQL Server 2005數據庫...是客戶端機器上所需的SQL Server 2005
- 23. JDBC java驅動程序sql server 2005
- 24. 如何在SQL Server 2005中從另一個SQL Server 2005中調用SQL腳本
- 25. 如何從程序SQL Server 2005中返回值到C#
- 26. 從SQL Server中引用.NET程序集存儲過程或函數
- 27. SQL Server 2005多維數據集維度查詢.Net
- 28. 集團在SQL Server 2000中工作,但不能在SQL Server 2005
- 29. Sql server 2005與ASP .NET編碼問題
- 30. 使用SQL Server 2005/2008接口.net MVC4
此方法在執行ext時正常工作每年也都是 - 你不需要去SQLCLR路線。看到我的回答低於 – piers7 2013-05-31 06:02:18