Sto cercando di aiutare un amico personale (che ora è anche un client) con un problema relativo CLR SQL. Ha un server SQL con un database che include 3 assembly .NET incorporati. Mi ha chiesto di aiutarlo a estrarre gli assembly dal database e salvarli come file .dll sul disco. È possibile?Estrazione di un assembly .NET da SQL Server 2005
risposta
Sì, questo è possibile. La rappresentazione binaria effettiva degli assiemi viene aggiornata in nel catalogo SQL per il server. Vale a dire, se si esegue un join tra sys.assembly_files e sys.assemblies, è possibile ottenere tutte le informazioni richieste da . Il binario degli assembly si trova nella colonna di contenuto della vista sys.assembly_files .
Ma al fine di estrarre la rappresentazione binaria da SQL Server e in un file su disco dovrete scrivere del codice .NET che deve eseguire sul stesso database in cui le assemblee che si riferiscono a si trovano ora. In Visual Studio avviare un progetto CLR SQL e aggiungere una classe ad esso con il seguente codice:
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();
}
}
}
}
}
quindi generare il progetto e distribuirlo al database. Assicurarsi che l'opzione di configurazione abilitata CLR sia abilitata su SQL Server. Questo è probabilmente già abilitato, dal momento che ci sono assiemi su di esso. Nel caso in cui l'esecuzione CLR non è abilitato è possibile eseguire il seguente codice su SQL Server Management Studio per attivarlo:
sp_configure 'clr enabled', 1
go
reconfigure
go
Una cosa che dovete essere consapevoli è il server SQL predefinita può non consentono di scrivere al disco dal codice .NET. Se si verifica un errore di sicurezza FileIO quando si esegue il codice sopra richiamando la stored procedure in SSMS, sarà necessario configurare il set di autorizzazioni appropriato per l'assembly . È possibile farlo tramite SSMS: fare clic con il pulsante destro del mouse sul nuovo assieme e controllare il set di autorizzazioni nella finestra di dialogo Proprietà. Impostalo su Accesso esterno. Ora si dovrebbe essere in grado di esportare i gruppi eseguendo il seguente codice nel SSMS:
exec SaveAssembly 'AssemblyName', 'f:\path\to\assemblyname.dll'
Spero che questo funziona per voi ...
Sì.
fare un select * from sys.assembly_files
Per trovare l'ID del gruppo che si desidera
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
impressionante. Semplice e pulito. Grazie. –
soluzione di Preet ha funzionato per me, ma ho dovuto configurare automazione per lavorare su SQL Server 2008 R2. Si noti inoltre che SaveToFile non funziona, né fornisce un messaggio di errore, a meno che SQL Server non disponga delle autorizzazioni per quella directory. Nel mio caso ho usato la cartella dati dell'istanza di SQL Server che ha funzionato bene.
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
approccio Jonas' funziona bene come una console app o uno script LINQPad anche - non c'è bisogno per il codice da eseguire localmente all'interno del processo di SQL, come egli suggerisce.ad esempio, l'estrazione del montaggio tSQLt (uno strumento di test) da un database:
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");
}
}
}
}
Prendendo soluzioni Preet e Nate e trasformandoli in uno script che esportare tutti i procs CLR utilizzando un cursore:
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
I Ho trovato una soluzione più semplice a questo problema, che era necessaria perché sp_OACreate
non sembra essere disponibile per SQL Server 2017 (almeno, non la versione Linux).
Si può semplicemente utilizzare l'utilità BCP di scrivere l'assemblea a un file su disco, in questo modo:
/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
E utilizzare questo file di formato (bcp.fmt):
13.0
1
1 SQLBINARY 0 0 "" 1 content ""
Il file risultante (/tmp/my_assembly.so) può essere utilizzato nella creazione di un assembly, ad esempio:
CREATE ASSEMBLY [MyAssembly] AUTHORIZATION [dbo]
FROM '/tmp/my_assembly.so' WITH PERMISSION_SET = SAFE;
- 1. Estrazione ore da un DateTime (SQL Server 2005)
- 2. Utilizzo di .Net 3.5 assembly SQL 2005 CLR?
- 3. SQL Server 2005 replica
- 4. Downgrade di SQL Server 2008 a SQL Server 2005
- 5. Isoweek in SQL Server 2005
- 6. Interrogazione di Active Directory da SQL Server 2005
- 7. Rimuovere sql server 2005 express per installare SQL Server 2008
- 8. Come aggiornare il risolutore di conflitti durante l'aggiornamento da SQL Server 2005 a SQL Server 2008
- 9. SQL Server 2005: come sottrarre sei mesi
- 10. Come ripristinare il database da MDF in SQL Server 2005?
- 11. SQL Server 2005 Error 701 - dalla memoria
- 12. SQL Server 2005 ROW_NUMBER() senza ORDER BY
- 13. SQL Server 2005 e ambito tabella temporaneo
- 14. sottoquery in UPDATE SET (sql server 2005)
- 15. Come recuperare i dati XML da SQL Server 2005?
- 16. Database SQL Server 2005 'In Recovery'
- 17. SQL Server 2005 Blocking Problem (ASYNC_NETWORK_IO)
- 18. Come creare un tipo di tabella in SQL Server 2005
- 19. Caricamento assembly WinRT da .NET
- 20. Sql server Integration Services Compatibilità 2008-2005
- 21. Concatenate ntext in SQL Server 2005
- 22. SQL Server 2005: Nullable Foreign Key Constraint
- 23. Come definire ENUM in SQL Server 2005?
- 24. SQL Server 2005 - Verifica valore DateTime nullo
- 25. Prestazioni MySQL vs SQL Server 2005/2008
- 26. SQL Server 2005 IsNumeric non cattura '0310D45'
- 27. Come utilizzare BIT in SQL Server 2005
- 28. Problema con estrazione data in SQL Server
- 29. SQL Server 2005: perché denominare le transazioni?
- 30. Estrazione di istruzioni SQL da un pacchetto SSIS/DTSX
Questo approccio funziona bene quando eseguito ext Anche da un punto di vista ernale - non è necessario seguire il percorso SQLCLR. Vedere la mia risposta sotto – piers7