Estoy tratando de ayudar a un amigo personal (que ahora también es un cliente) con un problema relacionado SQL CLR . Él tiene un servidor SQL con una base de datos que tiene 3 ensamblados .NET embebidos en él. Me pidió que lo ayudara a extraer los ensamblados desde la base de datos y guardarlos como archivos .dll en el disco. ¿Esto es posible?Extrayendo un ensamblado .NET de SQL Server 2005
Respuesta
Sí, esto es posible. La representación binaria real de los ensamblados en vivo en el catálogo de SQL para su servidor. A saber, si ejecuta una unión entre sys.assembly_files y sys.assemblies, puede obtener toda la información que necesita. El ensamblado binario se encuentra en la columna de contenido de la vista sys.assembly_files .
Pero con el fin de extraer la representación binaria de SQL Server y en un archivo en el disco tendrá que escribir código .NET que necesita ejecutarse en el misma base de datos, donde los montajes que se refieren a se encuentran ahora. En Visual Studio iniciar un proyecto SQL CLR y añadir una clase a la misma con el siguiente código:
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();
}
}
}
}
}
luego construir el proyecto e implementarlo en su base de datos. Asegúrese de que la opción de configuración habilitada de CLR esté habilitada en SQL Server. Esto es probablemente ya habilitado, ya que tiene ensamblados en él. En caso de ejecución CLR no es activado, puede ejecutar el siguiente código en SSMS para permitirle:
sp_configure 'clr enabled', 1
go
reconfigure
go
Una cosa más que usted necesita para tener en cuenta es el servidor SQL predeterminado puede no permitirá escribir en el disco desde el código .NET. Si obtiene un error de seguridad FileIO cuando ejecuta el código anterior llamando al procedimiento almacenado en SSMS, deberá configurar el conjunto de permisos adecuado para el ensamblaje . Puede hacerlo a través de SSMS: haga clic con el botón derecho en el nuevo ensamblaje y consulte el Conjunto de permisos en el cuadro de diálogo Propiedades. Establecerlo en Acceso Externo. Ahora debe ser capaz de exportar sus asambleas ejecutando el código siguiente en SSMS:
exec SaveAssembly 'AssemblyName', 'f:\path\to\assemblyname.dll'
Espero que esto funcione para usted ...
Sí.
hacer un select * from sys.assembly_files
para encontrar el id de la Asamblea desea
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
impresionante. Simple y limpio. Gracias. –
solución de Preet trabajó para mí, pero tuve que configurar automatización para trabajar en SQL Server 2008 R2. Tenga en cuenta también que SaveToFile no funciona, tampoco da un mensaje de error, a menos que SQL Server tenga permisos para ese directorio. En mi caso, utilicé la carpeta de datos de la instancia de SQL Server que funcionó bien.
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
enfoque Jonas' funciona bien como una aplicación de consola o un script LINQPad también - no hay necesidad de que el código que se ejecuta localmente dentro del proceso de SQL, ya que implica.por ejemplo, la extracción de la Asamblea tSQLt (una herramienta de prueba) a partir de una base de datos:
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");
}
}
}
}
Tomando soluciones Preet y Nate y convertirlos en un script que exportar todos procs clr utilizando un cursor:
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 han encontrado una solución más simple a este problema, que era necesaria porque sp_OACreate
no parece estar disponible para SQL Server 2017 (al menos, no la versión de Linux).
sólo puede utilizar la utilidad BCP para escribir el conjunto a un archivo en el disco, así:
/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
Y utilizar este archivo de formato (BCP.FMT):
13.0
1
1 SQLBINARY 0 0 "" 1 content ""
El El archivo resultante (/tmp/my_assembly.so) se puede usar en la creación de un ensamblaje, de la siguiente manera:
CREATE ASSEMBLY [MyAssembly] AUTHORIZATION [dbo]
FROM '/tmp/my_assembly.so' WITH PERMISSION_SET = SAFE;
- 1. Extrayendo [] alrededor de la columna en SQL Server 2005
- 2. SQL Server 2008 a SQL Server 2005
- 3. SQL Server 2005 replicación
- 4. Isoweek en SQL Server 2005
- 5. Acceda a TimeZoneInfo desde SQL 2005 Server
- 6. degradación de SQL Server 2008 a SQL Server 2005
- 7. Restaurar SQL Server 2008 DB * a * SQL Server 2005
- 8. SQL Server 2008 compatibilidad con SQL Server 2005
- 9. SQL Server 2005: T-SQL para deshabilitar temporalmente un desencadenador
- 10. Intercalación de clientes y SQL Server 2005
- 11. SQL Server 2005 pérdida de precisión numérica
- 12. SQL Server 2005 - Orden de combinaciones internas
- 13. SQL Server 2005: interbloqueo de transacción
- 14. Extraer horas de DateTime (SQL Server 2005)
- 15. ¿Dinámicamente nombrar índices en SQL Server 2005?
- 16. instrucción IIF en SQL Server 2005
- 17. Indexar varchar en MS SQL Server 2005
- 18. SQL Server 2005 Error 701 - sin memoria
- 19. Editar sinónimos en MS SQL Server 2005
- 20. SQL Server 2005 ROW_NUMBER() sin ORDER BY
- 21. sql server 2005 - exportar datos nvarchar (max)
- 22. TransactionInDoubtException usando System.Transactions en SQL Server 2005
- 23. UPSERT atómico en SQL Server 2005
- 24. Alcance de un CTE en SQL Server 2005
- 25. Crear un nuevo usuario de db en SQL Server 2005
- 26. Cómo crear un tipo de tabla en SQL Server 2005
- 27. MySQL vs SQL Server 2005/2008 rendimiento
- 28. subconsultas en UPDATE SET (sql server 2005)
- 29. Consultas jerárquicas en SQL Server 2005
- 30. Números persas en SQL Server 2005
Este enfoque funciona bien cuando se ejecuta ext también, no es necesario que vaya a la ruta SQLCLR. Ver mi respuesta a continuación – piers7