2010-11-09 8 views
9

Ho un'applicazione che recupera il testo delle stored procedure utilizzando sp_helptext. Funziona perfettamente su tutte le mie stored procedure eccetto per le stored procedure CLR. Se provo ad usare sp_helptext su una procedura SQLCLR memorizzato, ottengo questo errore:Ottieni l'istruzione CREATE T-SQL per le stored procedure SQLCLR

There is no text for object 'PROC_NAME'

So SSMS può farlo quando uso il "script come" -> "creare per" - il comando>.

Ma quando eseguo il trace dell'azione SSMS "generate script" con SQL Server Profiler, mi viene fornita una lunga lista di attività abbastanza complesse. Posso sfondare che se devo, ma qualcuno sa un modo semplice per ottenere programmaticamente il codice di un proc memorizzato CLR?

Modifica chiarimenti
Non voglio vedere il codice vero e proprio dal gruppo; Sto solo chiedendo un modo semplice per visualizzare il codice T-SQL , come in questo esempio:

CREATE PROCEDURE [dbo].[MY_PROC] 
    @PARAM1 [xml], 
    @PARAM2 [uniqueidentifier], 
    @PARAM3 [nvarchar](255), 
    @PARAM4[bit] = False 
WITH EXECUTE AS OWNER 
AS 
EXTERNAL NAME [SomeSolution.SomeProject].[SomeAssembly].[SomeMethod] 
GO 

In altre parole, il "lato server SQL" della funzione SQLCLR.

+0

Vuoi solo le stored procedure o anche funzioni, tipi, aggregati? –

risposta

3

Una procedura memorizzata CLR non avrà testo in quanto tale è un collegamento a una DLL. Avrete bisogno di ottenere il codice sorgente per la DLL

Vedi Common Language Runtime (CLR) Integration Programming Concepts ad esempio

+0

In suvote per te - hai perfettamente ragione, e ora mi rendo conto che la mia domanda era un po 'oscura. Si prega di consultare la mia revisione più recente. – JosephStyons

3

Risposta breve: no, non si può fare. (Almeno non programmaticamente/facilmente) Le procedure CLR vengono caricate da assembly .NET (file binari) e non esiste un modo semplice per ottenere il codice sorgente di tale file. Non all'interno di SQL Server. Ma è possibile utilizzare strumenti come RedGate Reflector per disassemblare DLL e visualizzare/recuperare il codice sorgente della stored procedure.

+0

In suvote per te - hai perfettamente ragione, e ora mi rendo conto che la mia domanda era un po 'oscura. Si prega di consultare la mia revisione più recente. – JosephStyons

1

In realtà, si può fare questo - ispezionando la vista sys.assembly_files catalogo:

SELECT CONVERT(VARCHAR(MAX), content) as my_source_code 
FROM sys.assembly_files 
+0

Questo restituisce solo un insieme di righe che dicono tutte "MZ" sul mio sistema – JosephStyons

+0

Cos'è MZ? Questo è quello che ottengo. – soulblazer

2

Ho avuto lo stesso dilemma e cercato più e più volte sul web per qualsiasi soluzione per ottenere il codice di una stored procedure CLR . Infine dovuto PROFILO ciò SSMS "generare script" l'azione ha fatto come hai detto e qui è quello che ho ottenuto:

--GET ALL CLR stored procedures 
SELECT 
sp.name AS [Name], 
sp.object_id AS [object_ID], 
case when amsp.object_id is null then N'''' else asmblsp.name end AS [AssemblyName], 
case when amsp.object_id is null then N'''' else amsp.assembly_class end AS [ClassName], 
case when amsp.object_id is null then N'''' else amsp.assembly_method end AS [MethodName] 
FROM 
sys.all_objects AS sp 
LEFT OUTER JOIN sys.assembly_modules AS amsp ON amsp.object_id = sp.object_id 
LEFT OUTER JOIN sys.assemblies AS asmblsp ON asmblsp.assembly_id = amsp.assembly_id 
LEFT OUTER JOIN sys.procedures AS spp ON spp.object_id = sp.object_id 
WHERE spp.type like 'PC' 

--For each CLR SP get the parameters in use 
SELECT 
param.name AS [Name] 
FROM 
sys.all_objects AS sp 
INNER JOIN sys.all_parameters AS param ON param.object_id=sp.object_id 
WHERE sp.name like 'your_sp_name' order by param.parameter_id ASC 

--For each parameter get the values, data type and so on... 
SELECT 
param.name AS [Name], 
param.parameter_id AS [param_ID], 
sp.object_id AS [object_ID], 
param.default_value AS [DefaultValue], 
usrt.name AS [DataType], 
sparam.name AS [DataTypeSchema], 
ISNULL(baset.name, N'''') AS [SystemType], 
CAST(CASE WHEN baset.name IN (N'nchar', N'nvarchar') AND param.max_length <> -1 THEN   param.max_length/2 ELSE param.max_length END AS int) AS [Length], 
CAST(param.precision AS int) AS [NumericPrecision], 
CAST(param.scale AS int) AS [NumericScale] 
FROM 
sys.all_objects AS sp 
INNER JOIN sys.all_parameters AS param ON param.object_id=sp.object_id 
LEFT OUTER JOIN sys.types AS usrt ON usrt.user_type_id = param.user_type_id 
LEFT OUTER JOIN sys.schemas AS sparam ON sparam.schema_id = usrt.schema_id 
LEFT OUTER JOIN sys.types AS baset ON (baset.user_type_id = param.system_type_id and  baset.user_type_id = baset.system_type_id) 
WHERE param.name='@param1' and sp.name='your_sp_name' 

Con questo script ho fatto uno script Perl per generare il codice per me. Immagino che da qui potresti fare lo stesso o creare la tua stored procedure per stampare il codice desiderato. Non sono un programmatore SQL, quindi non so come farlo, ma se qualcuno fa la programmazione delle domande sopra, per favore condividila.

+0

Grazie, questa è l'unica risposta corretta alla domanda reale. –

-2

È piuttosto facile, se si ha accesso a SQL Server Management Studio.

Fare clic con il pulsante destro del mouse sulla stored procedure CLR e quindi selezionare CREA SCRIPT - voilla.

CLRing felice.

-Danese.

+0

Come ho detto nella domanda: "So che il SSMS può farlo quando uso lo" script come "->" crea su "-> comando.". – JosephStyons

1

Abbiamo riscontrato un problema con le modifiche non aggiunte al controllo del codice sorgente, quindi ho eseguito le operazioni seguenti per ottenere gli aggiornamenti.

  1. utilizzando sqlservermanager ho chiesto tutte le sys.assembly_files a trovo quello che mi serviva.
  2. ha scritto un programma di console rapido per ottenere l'origine dei file che sono stati modificati.

    • Nel nostro caso è stato per i record che hanno un assembly_id di 68541 e di file multipli tutti hanno una file_id maggiore di 3

    • l'origine per il file cs è in un contenuto colonna chiamata e il nome del file è in una colonna di nome name. Ho convertito il contenuto in un array di byte e poi una stringa e ho scritto il contenuto in un file di testo usando filename.txt.

    • copia e passa il codice aggiornato e spinge al controllo del codice sorgente.

      using (SqlConnection conn = new SqlConnection(connstring)) 
      { 
          using (SqlCommand cmd = new SqlCommand("SELECT * FROM sys.assembly_files WHERE assembly_id = 68541 and file_id > 3", conn)) 
          { 
           DataTable ds = new DataTable(); 
           using (SqlDataAdapter da = new SqlDataAdapter(cmd)) 
           { 
            da.Fill(ds); 
            foreach (DataRow r in ds.Rows) 
            { 
             byte[] binaryString = (byte[])r["content"]; 
             string x = Encoding.UTF8.GetString(binaryString); 
             string filename = @"C:\SQLCLR"; 
             string filePath = string.Format(@"{0}\{1}.txt", filename,r["name"]); 
             File.WriteAllText(filePath, x); 
      
            } 
           } 
          } 
      } 
      
+1

In realtà questa è una risposta molto interessante poiché posizionerà il file sul PC piuttosto che sul server DB. Sono stato in grado di eseguirlo direttamente da LinqPad inserendo un valore per "connstring" e aggiornando la query con il mio "assembly_id". Ho anche modificato "File.WriteAllText (filePath, x);" a "File.WriteAllBytes (filePath, binaryString);" dato che i dati sono binari e volevo eseguirlo attraverso ILSpy che funzionava perfettamente. – Jay13

+1

Grazie mille. Questo mi ha fatto uscire da una marmellata. Sembrava che non avessimo verificato il codice sorgente effettivo, in quanto tale la DLL in produzione differiva parecchio dal codice sorgente che avevamo nel controllo del codice sorgente. Anche se suggerirò di modificare il codice come segue affinché la DLL sia effettivamente caricabile: 'codice stringa nomefile = @" C: \ SQLCLR "; \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t \t // stringa filePath = string.Format (@ "{0} \ {1} .txt", il nome del file, "NameOfYourDll.dll"); File.WriteAllBytes (filePath, binaryString); ' – miniGweek

0

per estrarre il assambly gestiscono questo:

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, 'D:\SqlServerProject1.dll', 2 
    EXEC sp_OAMethod @ObjectToken, 'Close' 
    EXEC sp_OADestroy @ObjectToken 

Poi decompilare con Redgate riflettore o qualsiasi decompilatore .Net (ilspy, ...)

0
  1. A differenza di oggetti T-SQL simili, le istruzioni CREATE [ STORED PROCEDURE | FUNCTION | TRIGGER | TYPE | AGGREGATE ] ... per SQLCLR o gli oggetti non vengono archiviati così come sono; sono derivati ​​tramite il tipo di oggetto e una combinazione di sys.assemblies, sys.assembly_modules, sys.parameters, sys.types e sys.assembly_types.

    Se si sta tentando di creare queste istruzioni CREATE in T-SQL o in un altro linguaggio diverso da.NET, è necessario selezionare i dati appropriati da tali tabelle e raggrupparli tutti insieme. Tuttavia, se si utilizza .NET, è possibile utilizzare Scripter Class nella libreria SMO (Microsoft.SqlServer.Smo.dll). Dovrebbe essere in grado di scrivere qualsiasi cosa in SQL Server. E infatti, dovresti probabilmente usarlo per scrivere tutto per il tuo strumento invece di usare le query.

  2. Al di fuori della visualizzazione stored procedure/funzione/trigger definizioni al volo in SSMS (cioè veloce e facile), non si dovrebbe usare sp_helptext per estrarre le definizioni dell'oggetto. Si fa un sacco di lavoro inutile in quanto sembra essere solo minorly aggiornato dal SQL Server 2000. I due problemi principali con esso sono:

    1. Non gestisce le linee individuali che sono> 4000 caratteri
    2. E ' consente solo le nuove righe CRLF (ovvero \r\n), non nuove LF (ovvero \n) valide.

    È possibile vedere questo visualizzando la definizione di tale stored procedure di sistema:

    EXEC sp_helptext 'sp_helptext'; 
    

    Invece, si dovrebbe utilizzare la funzione built-in OBJECT_DEFINITION() (che prende un object_id come input) oppure selezionare da una delle viste del catalogo di sistema che contengono queste definizioni: sys.sql_modules, sys.server_sql_modules, sys.system_sql_modules e sys.system_sql_modules.

Problemi correlati