2010-11-05 8 views
15

मैं एक एसक्यूएल सीएलआर संबंधित समस्या के साथ एक निजी मित्र (जो अब भी एक ग्राहक है) की मदद करने की कोशिश कर रहा हूं। उसके पास एक डेटाबेस के साथ एक SQL सर्वर है जिसमें 3 .NET असेंबली इसमें एम्बेड किया गया है। उन्होंने मुझे डेटाबेस से असेंबली निकालने में मदद करने के लिए कहा और उन्हें डिस्क पर .dll फ़ाइलों के रूप में सहेजें। क्या यह भी संभव है?एसक्यूएल सर्वर 2005 से एक .NET असेंबली निकालने

उत्तर

12

हां, यह संभव है। असेंबली का वास्तविक बाइनरी प्रतिनिधित्व आपके सर्वर के लिए SQL कैटलॉग में रहता है। अर्थात्, यदि आप sys.assembly_files और sys.assemblies के बीच जुड़ते हैं तो आप की सभी जानकारी प्राप्त कर सकते हैं। असेंबली बाइनरी sys.assembly_files व्यू के सामग्री कॉलम में है।

लेकिन आदेश एसक्यूएल सर्वर से और आप कुछ नेट कोड एक ही डाटाबेस जहां विधानसभाओं का उल्लेख अब स्थित हैं पर चलने की जरूरत है कि लिखने के लिए होगा डिस्क पर एक फ़ाइल में द्विआधारी प्रतिनिधित्व निकालने के लिए में। दृश्य स्टूडियो में एक 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 सर्वर पर सक्षम कॉन्फ़िगरेशन विकल्प सक्षम है। यह शायद पहले से ही सक्षम है, क्योंकि आपके पास इस पर असेंबली हैं।

sp_configure 'clr enabled', 1 
go 

reconfigure 
go 

एक और बात यह है कि आप के बारे में पता करने की आवश्यकता है डिफ़ॉल्ट एसक्यूएल सर्वर द्वारा है आप लिखने की अनुमति नहीं हो सकता है: मामले में clr निष्पादन नहीं सक्षम आप इसे सक्षम करने के लिए पर SSMS निम्नलिखित कोड चलाया जा सकता है .NET कोड से डिस्क पर। अगर आपको एसएसएमएस में संग्रहीत प्रक्रिया को कॉल करके उपरोक्त कोड चलाते समय फ़ाइलियो सुरक्षा त्रुटि प्राप्त होती है, तो आपको असेंबली के लिए उचित अनुमति सेट कॉन्फ़िगर करने की आवश्यकता होगी। आप एसएसएमएस के माध्यम से ऐसा कर सकते हैं: नई असेंबली पर राइट-क्लिक करें और गुण संवाद में अनुमति सेट देखें। इसे बाहरी एक्सेस पर सेट करें। अब आप SSMS में निम्नलिखित कोड चलाकर अपने विधानसभाओं निर्यात करने के लिए सक्षम होना चाहिए:

exec SaveAssembly 'AssemblyName', 'f:\path\to\assemblyname.dll' 

आशा यह आपके लिए काम करता है ...

+0

यह दृष्टिकोण ठीक काम करता है जब ext मार डाला कभी भी - आपको SQLCLR मार्ग पर जाने की आवश्यकता नहीं है। – piers7

8

हां।

एक 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 
+0

भयानक नीचे मेरा उत्तर देखें। सरल और साफ धन्यवाद। –

3

प्रीत का समाधान मेरे लिए काम किया है, लेकिन मैं ओले स्वचालन कॉन्फ़िगर करने के लिए एसक्यूएल सर्वर 2008 R2 पर काम करने के लिए किया था। ध्यान दें कि SaveToFile काम नहीं करता है - न ही यह एक त्रुटि संदेश देता है - जब तक कि SQL सर्वर को उस निर्देशिका की अनुमति न हो। मेरे मामले में मैंने SQL सर्वर इंस्टेंस के डेटा फ़ोल्डर का उपयोग किया जो ठीक काम करता था।

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 
6

जोनास 'दृष्टिकोण एक कंसोल एप्लिकेशन या LINQPad स्क्रिप्ट के रूप में भी ठीक काम करता है - कोई जरूरत के लिए कोड, एसक्यूएल प्रक्रिया के भीतर स्थानीय स्तर पर निष्पादित किया जाना है के रूप में वह तात्पर्य नहीं है।जैसे किसी डेटाबेस से 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"); 
      } 
     } 
    } 
} 
0

प्रीत और नैट के समाधान ले रहा है और उन्हें एक स्क्रिप्ट है कि एक कर्सर का उपयोग करके सभी clr procs निर्यात करेगा में बदल:

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 
0

मैं इस समस्या का एक आसान समाधान मिला है, जो आवश्यक था क्योंकि sp_OACreate SQL सर्वर 2017 (कम से कम, लिनक्स संस्करण नहीं) के लिए उपलब्ध प्रतीत नहीं होता है।

तुम बस बीसीपी उपयोगिता, डिस्क पर एक फ़ाइल में विधानसभा लिखने के लिए तो जैसे उपयोग कर सकते हैं:

/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; 
संबंधित मुद्दे