none
Listar parâmetros de entrada de uma proc, e quais são opcionais. RRS feed

  • Pergunta

  • Recentemente enfrentei o seguinte problema: Queria listar os parâmetros de entrada de uma proc. Parece simples, estando as informações disponíveis na tabela syscolumns.

    Entretanto, quando na declaração de um parâmetro da proc definimos um valor padrão, o mesmo pode ser omitido na chamada da proc, como neste exemplo:

    CREATE PROCEDURE SP_TESTE( 
    @P_A AS INT,
    @P_B AS CHAR(10) = 'teste')
    AS
    BEGIN
    PRINT 'Alô mundo! - ' + RTRIM(CONVERT(CHAR,@P_A)) + ' - ' + @P_B
    RETURN
    END

    Aqui, na chamada da proc SP_TESTE, o parâmetro @P_A é obrigatório, mas @P_B pode ser omitido e valerá 'teste', por padrão.

    Depois de muito procurar por uma solução, a única maneira que descobri foi, através de T-SQL, pegar o código da proc (com o sp_helptext), eliminar todos os comentários, filtrar o pedaço onde consta somente a declaração e, então, verificar quais parâmetros possuem valor default definido através do sinal de igual (=).

    Este script, ao final de sua execução, retorna 2 tabelas: um resumo sobre a proc analisada (com uma coluna chamada "Opcional") e o código da declaração da proc, sem comentários.

    Estou postando-o para salvar quem tenha o mesmo problema que eu, e aceito sugestões para melhorias.

    *****************************************************************************************************

    DECLARE @NOME_PROC SYSNAME
    SELECT @NOME_PROC = 'sp_teste'

    SET NOCOUNT ON

    DECLARE @Aux_Param        SYSNAME
    DECLARE @Aux_Tipo        VARCHAR(30)
    DECLARE @Aux_Int        INT
    DECLARE @Aux_Int2        INT

    /*
     * Tabela temporária que armazena os dados sobre os parâmetros da proc. O campo "Opcional"
     * é preenchido somente posteriormente, pois deve ser analisado o código-fonte da proc.
     */
    CREATE TABLE #PROC_PARAMS
    (
            Nome_Parametro      SYSNAME,
            Tipo_Usuario        VARCHAR(30),
            Tipo_Primitivo      VARCHAR(10),
            Tamanho             INT,
            Digitos_Int         INT,
            Digitos_Dec         INT,
            Opcional            INT,
            Ordem               INT,
            Indice              INT IDENTITY NOT NULL
    )

    /*
     * Possui os mesmos registros de #PROC_PARAMS. Nela, à medida que é verificado se um parâmetro
     * é opcional, o registro do mesmo é apagado desta tabela.
     */
    CREATE TABLE #PROC_BUSCA_PARAMS
    (
            Nome_Parametro        SYSNAME,
            Tipo_Usuario        VARCHAR(30),
            Indice                 INT
    )

    /*
     * Tabela que carrega o código-fonte da declaração da proc. Nela serão procuradas ocorrências
     * do tipo "Parametro As Tipo" . Caso não haja na linha um sinal de "=", entende-se que o
     * parâmetro não possui valor default e não pode ser omitido na chamada da proc.
     * Os dados nela serão filtrados de forma a restar somente a declaração da proc,
     * sem comentários (caso existam)
     */
    CREATE TABLE #PROC_CODE
    (
            Codigo                VARCHAR(200),
            Tipo_Comentario        INT,
            Indice                 INT IDENTITY NOT NULL,
    )


    /* **************************** */
    /* ALIMENTA A TABELA #PROC_CODE */
    /* **************************** */

            CREATE         TABLE        #PROC_CODE_AUX    ( Codigo VARCHAR(200) )
            INSERT         INTO         #PROC_CODE_AUX    EXEC sp_helptext @nome_proc
            INSERT         INTO         #PROC_CODE        SELECT *, 0 FROM #PROC_CODE_AUX
            DROP           TABLE        #PROC_CODE_AUX

    /* ************************************************* */
    /* APAGA OS COMENTARIOS DA PROC, PARA EVITAR ENGANOS */
    /* ************************************************* */

            -- Marca o campo Tipo_Comentario com 1 quando na linha só começa um comentário (/*),
            -- com 2 quando só termina (*/) e com 3 se o comentário começa e termina na mesma linha.
            -- Caso na linha não haja /* nem */, ficara com 0
            UPDATE         #PROC_CODE
            SET            Tipo_Comentario = 1
            WHERE          Codigo LIKE '%/*%'
           
            UPDATE         #PROC_CODE
            SET            Tipo_Comentario = Tipo_Comentario + 2
            WHERE          Codigo LIKE '%*/%'
           
            -- Pega os pares de linhas marcados Tipo_Comentario 1 e 2, e apaga as linhas entre elas.
            -- A cada bloco cujo "miolo" é apagado, troca Tipo_Comentario de 1 e 2 para 10 e 20.
            -- Quando não houverem mais linhas com Tipo_Comentario valendo 1 nem 2, sai do WHILE
            WHILE
                EXISTS (SELECT Indice FROM #PROC_CODE WHERE Tipo_Comentario = 1 OR Tipo_Comentario = 2)
                BEGIN
           
                    SELECT @Aux_Int = MIN(Indice) FROM #PROC_CODE WHERE Tipo_Comentario = 1
                    SELECT @Aux_Int2 = MIN(Indice) FROM #PROC_CODE WHERE Tipo_Comentario = 2
           
           
                    DELETE  FROM #PROC_CODE
                    WHERE   Indice > @Aux_Int
                    AND     Indice < @Aux_Int2
           
                    UPDATE  #PROC_CODE
                    SET     Tipo_Comentario = Tipo_Comentario * 10
                    WHERE   Indice = @Aux_Int
                    OR      Indice = @Aux_Int2
                END
           
            -- Nas linhas com Tipo_Comentario 10 e 20, limpa tudo que estiver à frente de
            -- /* ou atrás de */, respectivamente
            UPDATE     #PROC_CODE
            SET        Codigo = SUBSTRING (Codigo, 1, PATINDEX ('%/*%', Codigo) - 1 )
            WHERE      Codigo like '%/*%'
            AND        Tipo_Comentario = 10
           
            UPDATE     #PROC_CODE
            SET        Codigo = SUBSTRING (Codigo, PATINDEX ('%*/%', Codigo) + 2, Len(Codigo))
            WHERE      Codigo like '%*/%'
            AND        Tipo_Comentario = 20
           
            -- Nas linhas com Tipo_Comentario 3, apaga tudo o que estiver entre /* e */,
            -- inclusive estes delimitadores de comentário
            UPDATE     #PROC_CODE
            SET        Codigo = SUBSTRING (Codigo, 1, PATINDEX ('%/*%', Codigo) - 1 ) +
                                SUBSTRING (Codigo, PATINDEX ('%*/%', Codigo) + 2, Len(Codigo))
            WHERE      Codigo like '%/*%*/%'
            AND        Tipo_Comentario = 3
           
            -- Agora não há mais comantários do tipo /* ... */ no código.
           
            -- Limpa tudo o que estiver à frente de "--", inclusive este indicador de comentário
            UPDATE      #PROC_CODE
            SET         Codigo = SUBSTRING (Codigo, 1, PATINDEX ('%--%', Codigo) - 1 )
            WHERE       Codigo like '%--%'
           
            -- Pega a linha onde está o comando AS do início do código da proc e apaga tudo que é
            -- posterior a ela.
            -- Considerando que não há mais comentários na proc e para evitar confundir com
            -- declarações de parâmetros da proc na forma VARIAVEL AS TIPO, considera-se que na linha
            -- onde está esse comando AS, só podem haver ele, comentários e, opcionalmente, o comando
            -- BEGIN.
            -- Mesmo assim, ainda mantém a linha onde localiza-se o comando AS, para evitar apagar um
            -- parâmetro, caso aconteça de estarem na mesma linha.
           
            DELETE #PROC_CODE
            WHERE Indice > ANY
                    (
                            SELECT    Indice FROM #PROC_CODE
                            WHERE     Codigo LIKE '%AS%'
                            AND       LEN(RTRIM(REPLACE(Codigo, 'AS', ''))) = 2 -- SOMENTE "AS"
                            OR        LTRIM(RTRIM(Codigo)) LIKE 'AS%BEGIN%'     -- SOMENTE "AS BEGIN" e espaços
                            OR        RTRIM(Codigo) LIKE '%)%AS%'               -- "AS" na mesma linha que um parâmetro
                    )

            -- Apaga os comandos AS.
            UPDATE     #PROC_CODE
            SET        Codigo = REPLACE(Codigo, 'AS', '')

            -- Apaga o comando BEGIN, caso ainda tenha restado no código
            UPDATE     #PROC_CODE
            SET        Codigo = REPLACE(Codigo, 'BEGIN', '')
            WHERE      Indice IN
                       (SELECT MAX(Indice) FROM #PROC_CODE)
           
            -- Apaga as linhas em branco
            DELETE     #PROC_CODE
            WHERE      LEN(LTRIM(RTRIM(Codigo))) <= 2

    /* ************************************************** */
    /* INSERE NA TABELA DE RESULTADO AS INFORMAÇÕES SOBRE */
    /* A PROC EXTRAÍDAS DAS TABELAS DE SISTEMA.           */
    /* AINDA NÃO VERIFICA SE UM CAMPO É OPCIONAL              */
    /* ************************************************** */

            INSERT INTO #PROC_PARAMS
           
                    SELECT  SCOL.name,
                            STU.name,
                            STY.name,
                            SCOL.length,
                            SCOL.xprec - SCOL.xscale,
                            SCOL.xscale,
                            0,       
                            SCOL.colorder
           
                    FROM sysobjects SOBJ
                   
                    JOIN syscolumns SCOL
                    ON SCOL.Id = SOBJ.Id
                   
                    JOIN systypes STU
                    ON STU.xusertype = SCOL.xusertype
                   
                    JOIN systypes STY
                    ON STY.xusertype = SCOL.xtype
                   
                    WHERE SOBJ.NAME = @nome_proc
                   
                    ORDER BY SCOL.colorder

    /* *********************************************** */
    /* VERIFICA QUAIS PARAMETROS DA PROC SAO OPCIONAIS */
    /* *********************************************** */

            -- Preenche a tabela #PROC_BUSCA_PARAMS com dados dos parâmetros de entrada
            -- da proc. À medida que cada parâmetro for analisado, a linha correspondente
            -- nessa tabela será apagada, e isso se repetirá até ela ficar vazia.
            INSERT  INTO      #PROC_BUSCA_PARAMS
                    SELECT    Nome_Parametro, Tipo_Usuario, Indice
                    FROM      #PROC_PARAMS
           
            WHILE EXISTS (SELECT Indice FROM #PROC_BUSCA_PARAMS)
                BEGIN
           
                    -- Como estes 2 selects logo abaixo passarão às variáveis os valores da última
                    -- linha, eles são feitos ao contrário (Indice decrescente), para pegar os valores
                    -- na ordem correta.
                    SELECT @Aux_Param = Nome_Parametro FROM #PROC_BUSCA_PARAMS ORDER BY Indice DESC
                    SELECT @Aux_Tipo = Tipo_Usuario FROM #PROC_BUSCA_PARAMS ORDER BY Indice DESC
                    SELECT @Aux_Int = Indice FROM #PROC_BUSCA_PARAMS ORDER BY Indice DESC
           
                    PRINT 'Procurando no código pelo parâmetro: ' + @Aux_Param + ' ' + @Aux_Tipo
           
                    -- Verifica se na linha onde o parâmetro atual é declarado aparece um sinal de igual.
                    -- Se aparecer, entende-se que aquele parâmetro possui um valor default e pode ser
                    -- omitido na chamada da proc.
                    IF EXISTS (SELECT Codigo FROM #PROC_CODE WHERE Codigo LIKE '%' + @Aux_Param + '%' + @Aux_Tipo + '%=%')
                        BEGIN
                            PRINT 'Opcional: SIM'
                            UPDATE #PROC_PARAMS SET Opcional = 1 WHERE Indice = @Aux_Int
                        END
                    ELSE
                        BEGIN
                            PRINT 'Opcional: NAO'
                        END
           
                    -- Depois que já utilizou um registro de #PROC_BUSCA_PARAMS, apaga-o da tabela.
                    DELETE #PROC_BUSCA_PARAMS WHERE Indice IN ( SELECT TOP 1 Indice FROM #PROC_BUSCA_PARAMS)
           
                    PRINT ''
           
                END

    /* *********************************************** */
    /* RETORNA 2 TABELAS: O RESUMO DA PROC ANALISADA E */
    /* O CABEÇALHO DA MESMA                            */
    /* *********************************************** */

            -- Retorno 1
            SELECT  Nome_Parametro,
                    Tipo_Usuario,
                    Tipo_Primitivo,
                    Tamanho,
                    Digitos_Int,
                    Digitos_Dec,
                    Opcional,
                    Ordem
            FROM #PROC_PARAMS

            -- Retorno 2
            SELECT Declaracao = Codigo FROM #PROC_CODE


    /* ************************* */
    /* APAGA TABELAS TEMPORÁRIAS */
    /* ************************* */

            DROP TABLE #PROC_BUSCA_PARAMS
            DROP TABLE #PROC_PARAMS
            DROP TABLE #PROC_CODE

    sexta-feira, 16 de fevereiro de 2007 19:16

Respostas

  • Versão melhorada, com suporte a comentários mal intencionados e na versão Stored Procedure ao invés de script. Código totalmente comentado.

    /*
     * Analisa os parâmetros de entrada de uma Stored Procedure.
     * Quando uma proc possui um valor default para um parâmetro,
     * o mesmo pode ser omitido na chamada dela. Mas essa informação
     * não é armazenada no banco quando a proc é compilada.
     * Por isso, esta Stored Procedure retorna uma coluna chamada
     * Opcional, que reflete esta situação.
     */

    CREATE PROCEDURE Sp_Analisa_Parametros_Proc @Nome_Proc SYSNAME
           
    AS

    SET NOCOUNT ON

    DECLARE @Aux_Param        SYSNAME
    DECLARE @Aux_Tipo         VARCHAR(30)
    DECLARE @Aux_Int          INT
    DECLARE @Aux_Int2         INT

    /*
     * Tabela temporária que armazena os dados sobre os parâmetros da proc. O campo "Opcional"
     * é preenchido somente posteriormente, pois deve ser analisado o código-fonte da proc.
     */
    CREATE TABLE #PROC_PARAMS
    (
            Nome_Parametro        SYSNAME,
            Tipo_Especifico       VARCHAR(30),
            Tipo_Primitivo        VARCHAR(10),
            Tamanho               INT,
            Digitos_Int           INT,
            Digitos_Dec           INT,
            Opcional              INT,
            Ordem                 INT,
            Indice                INT IDENTITY NOT NULL
    )

    /*
     * Possui os mesmos registros de #PROC_PARAMS. Nela, à medida que é verificado se um parâmetro
     * é opcional, o registro do mesmo é apagado desta tabela.
     */
    CREATE TABLE #PROC_BUSCA_PARAMS
    (
            Nome_Parametro         SYSNAME,
            Tipo_Especifico        VARCHAR(30),
            Indice                 INT
    )

    /*
     * Tabela que carrega o código-fonte da declaração da proc. Nela serão procuradas ocorrências
     * do tipo "Parametro As Tipo" . Caso não haja na linha um sinal de "=", entende-se que o
     * parâmetro não possui valor default e não pode ser omitido na chamada da proc.
     * Os dados nela serão filtrados de forma a restar somente a declaração da proc,
     * sem comentários (caso existam)
     */
    CREATE TABLE #PROC_CODE
    (
            Codigo                 VARCHAR(200),
            Tipo_Comentario        INT DEFAULT 0,
            Indice                 INT IDENTITY NOT NULL,
    )


    /* **************************** */
    /* ALIMENTA A TABELA #PROC_CODE */
    /* **************************** */

            INSERT        #PROC_CODE
                         (Codigo)
            EXEC sp_helptext @nome_proc
           

    /* ************************************************* */
    /* APAGA OS COMENTARIOS DA PROC, PARA EVITAR ENGANOS */
    /* ************************************************* */

            -- Marca o campo Tipo_Comentario com 1 quando na linha só começa um comentário (/*),
            -- com 2 quando só termina (*/) e com 3 se o comentário começa e termina na mesma linha.
            -- Caso na linha não haja /* nem */, ficará com 0

            -- Marca campos com bloco de comentário comenándo e terminando na mesma linha

            UPDATE        #PROC_CODE
            SET           Tipo_Comentario = 3
            WHERE         Codigo LIKE '%/*%*/%'

            -- Nas linhas com Tipo_Comentario 3, apaga tudo o que estiver entre /* e */,
            -- inclusive estes delimitadores de comentário

            WHILE EXISTS ( SELECT Codigo FROM #PROC_CODE WHERE Codigo LIKE '%/*%*/%' AND Tipo_Comentario = 3)
            BEGIN

                    -- Pega os trechos antes e depois do comentário
                    UPDATE  #PROC_CODE
                    SET     Codigo = SUBSTRING (Codigo, 1, PATINDEX ('%/*%', Codigo) - 1 ) +
                                  SUBSTRING
                                  (
                                         SUBSTRING (Codigo, PATINDEX ('%/*%', Codigo) + 2 , Len(Codigo)) ,
                                         PATINDEX ('%*/%',
                                                     SUBSTRING (Codigo, PATINDEX ('%/*%', Codigo) + 2 , Len(Codigo)) ) + 2,
                                         Len(Codigo)
                                  ),
                            Tipo_Comentario = 0
                    WHERE   Codigo LIKE '%/*%*/%'
                    AND     Tipo_Comentario = 3

                    -- Marca campos com bloco de comentário comenándo e terminando na mesma linha
                    -- Vai repetir isso até acabar com todos os blocos de uma linha

                    UPDATE  #PROC_CODE
                    SET     Tipo_Comentario = 3
                    WHERE   Codigo LIKE '%/*%*/%'

            END
           
            -- Agora não há mais comantários do tipo /* ... */ no código.

            -- Marca campos de início de bloco com Tipo_Comentario = 1 e fim de bloco
            -- com Tipo_Comentario = 2

            UPDATE  #PROC_CODE
            SET     Tipo_Comentario = 1
            WHERE   Codigo LIKE '%/*%'
           
            UPDATE  #PROC_CODE
            SET     Tipo_Comentario = 2
            WHERE   Codigo LIKE '%*/%'
            AND     Tipo_Comentario <> 2

            -- Pega os pares de linhas marcados com Tipo_Comentario 1 e 2, e apaga as linhas ENTRE elas
            -- (os miolos dos blocos de comentário).
            -- A cada bloco cujo "miolo" é apagado, troca Tipo_Comentario de 1 e 2 para 10 e 20.
            -- Quando não houverem mais linhas com Tipo_Comentario valendo 1 nem 2, não haverá mais
            -- miolos de comentários e sai do WHILE
            WHILE EXISTS (SELECT Indice FROM #PROC_CODE WHERE Tipo_Comentario = 1 OR Tipo_Comentario = 2)
            BEGIN
                    SELECT  @Aux_Int = MIN(Indice) FROM #PROC_CODE WHERE Tipo_Comentario = 1
                    SELECT  @Aux_Int2 = MIN(Indice) FROM #PROC_CODE WHERE Tipo_Comentario = 2
           
                    DELETE  FROM #PROC_CODE
                    WHERE   Indice > @Aux_Int
                    AND     Indice < @Aux_Int2

                    UPDATE  #PROC_CODE
                    SET     Tipo_Comentario = Tipo_Comentario * 10
                    WHERE   Indice = @Aux_Int
                    OR      Indice = @Aux_Int2
            END

            -- Nas linhas com Tipo_Comentario 10 e 20, limpa tudo que estiver à frente de
            -- "/*" ou atrás de "*/", respectivamente
            UPDATE  #PROC_CODE
            SET     Codigo = SUBSTRING (Codigo, 1, PATINDEX ('%/*%', Codigo) - 1 )
            WHERE   Codigo LIKE '%/*%'
            AND     Tipo_Comentario = 10

            UPDATE  #PROC_CODE
            SET     Codigo = SUBSTRING (Codigo, PATINDEX ('%*/%', Codigo) + 2, Len(Codigo))
            WHERE   Codigo LIKE '%*/%'
            AND     Tipo_Comentario = 20

            -- Agora, trata os casos em que um bloco terminou em uma linha e outro começou na mesma
            -- linha. Neste caso, o início do bloco ficou marcado com Tipo_Comentário = 20, o miolo
            -- não foi apagado e ficou com 0 e a linha onde o fim do bloco estava ficou marcada com
            -- 20, mas o trecho de fim de comentário "*/" não consta mais.

            -- Tudo o que estiver entre uma linha Tipo_Comentario = 20 que contenha "/*" e a próxima linha
            -- Tipo_Comentario = 20, é miolo e deve ser apagado.
            -- Marca os inícios de bloco cujo miolo já foi apagado com 200, até que não restem mais linhas
            -- Tipo_Comentario = 20 contendo "/*"
            WHILE EXISTS (SELECT Indice FROM #PROC_CODE WHERE Tipo_Comentario = 20 AND Codigo LIKE '%/*%')
            BEGIN
                    -- Pega uma linha Tipo_Comentario = 20 e que tenha "/*"

                    SELECT  @Aux_Int = MIN(Indice) FROM #PROC_CODE WHERE Tipo_Comentario = 20 AND Codigo LIKE '%/*%'
                    -- Pega a próxima linha com Tipo_Comentario = 20, depois da linha @Aux_Int
                    SELECT  @Aux_Int2 = MIN(Indice) FROM #PROC_CODE WHERE Tipo_Comentario = 20 AND Indice > @Aux_Int
           
                    -- Apaga o miolo
                    DELETE  FROM #PROC_CODE
                    WHERE   Indice > @Aux_Int
                    AND     Indice < @Aux_Int2
           
                    -- Marca o início do bloco
                    UPDATE  #PROC_CODE
                    SET     Tipo_Comentario = Tipo_Comentario * 10
                    WHERE   Indice = @Aux_Int

                    -- Caso o fim do bloco (Indice=@Aux_Int2) não possua mais outro início
                    -- de comentário "/*", marca-o com Tipo_Comentario = 0
                    UPDATE  #PROC_CODE
                    SET     Tipo_Comentario = 0
                    WHERE   Indice = @Aux_Int2
                    AND     Codigo NOT LIKE '%/*%'
            END

            -- Depois de apagado os miolos, apaga os trechos de início de comentário.
            UPDATE  #PROC_CODE
            SET     Codigo = SUBSTRING (Codigo, 1, PATINDEX ('%/*%', Codigo) - 1 ),
                    Tipo_Comentario = 0
            WHERE   Codigo LIKE '%/*%'
            AND     Tipo_Comentario = 200

            -- Limpa tudo o que estiver à frente de "--", inclusive o indicador de comentário
            UPDATE  #PROC_CODE
            SET     Codigo = SUBSTRING (Codigo, 1, PATINDEX ('%--%', Codigo) - 1 )
            WHERE   Codigo LIKE '%--%'
           
            -- Pega a linha onde está o comando AS do início do código da proc e apaga tudo que é
            -- posterior a ela.
            -- Considerando que não há mais comentários na proc e para evitar confundir com
            -- declarações de parâmetros da proc na forma VARIAVEL AS TIPO, considera-se que na linha
            -- onde está esse comando AS, só podem haver ele, comentários e, opcionalmente, o comando
            -- BEGIN.
            -- Mesmo assim, ainda mantém a linha onde localiza-se o comando AS, para evitar apagar um
            -- parâmetro, caso aconteça de estarem na mesma linha.

            UPDATE  #PROC_CODE
            SET     Tipo_Comentario = LEN(LTRIM(RTRIM(REPLACE(Codigo, 'AS', ''))))
            WHERE   Indice = 9
           
            DELETE  #PROC_CODE
            WHERE   Indice > ANY
                    (
                            SELECT         Indice FROM #PROC_CODE
                            WHERE         Codigo LIKE '%AS%'
                            AND         LEN(LTRIM(RTRIM(REPLACE(Codigo, 'AS', '')))) = 2        -- SOMENTE "AS".
                            OR        LTRIM(RTRIM(Codigo)) LIKE '%AS%BEGIN%'                          -- SOMENTE "AS BEGIN" e espaços.
                            OR        RTRIM(Codigo) LIKE '%)%AS%'                                  -- "AS" na mesma linha que um parâmetro,
                                                                                            -- mas depois do mesmo.
                    )


            -- Apaga os comandos AS.
            UPDATE  #PROC_CODE
            SET     Codigo = REPLACE(Codigo, 'AS', '')

            -- Apaga o comando BEGIN, caso ainda tenha restado no código
            UPDATE  #PROC_CODE
            SET     Codigo = REPLACE(Codigo, 'BEGIN', '')
            WHERE   Indice IN
                    (SELECT MAX(Indice) FROM #PROC_CODE)
           
            -- Tira retorno de carro e quebra de linha, aplica trim e zera Tipo_Comentario
            UPDATE  #PROC_CODE
            SET     Codigo = LTRIM(RTRIM(REPLACE(

                                    REPLACE(
                                            Codigo,
                                            CHAR(10),
                                            ''),
                                    CHAR(13),
                                    ''))),
                    Tipo_Comentario = 0

            -- Apaga as linhas em branco
            DELETE  #PROC_CODE
            WHERE   LEN(LTRIM(RTRIM(Codigo))) <= 2

    /* ************************************************** */
    /* INSERE NA TABELA DE RESULTADO AS INFORMAÇÕES SOBRE */
    /* A PROC EXTRAÍDAS DAS TABELAS DE SISTEMA.           */
    /* AINDA NÃO VERIFICA SE UM CAMPO É OPCIONAL              */
    /* ************************************************** */

            INSERT INTO #PROC_PARAMS
           
                    SELECT  SCOL.name,
                            STU.name,
                            STY.name,
                            SCOL.length,
                            SCOL.xprec - SCOL.xscale,
                            SCOL.xscale,
                            0,       
                            SCOL.colorder
           
                    FROM sysobjects SOBJ
                   
                    JOIN syscolumns SCOL
                    ON SCOL.Id = SOBJ.Id
                   
                    JOIN systypes STU
                    ON STU.xusertype = SCOL.xusertype
                   
                    JOIN systypes STY
                    ON STY.xusertype = SCOL.xtype
                   
                    WHERE SOBJ.NAME = @nome_proc
                   
                    ORDER BY SCOL.colorder

    /* *********************************************** */
    /* VERIFICA QUAIS PARAMETROS DA PROC SAO OPCIONAIS */
    /* *********************************************** */

            -- Preenche a tabela #PROC_BUSCA_PARAMS com dados dos parâmetros de entrada
            -- da proc. À medida que cada parâmetro for analisado, a linha correspondente
            -- nessa tabela será apagada, e isso se repetirá até ela ficar vazia.
            INSERT  INTO #PROC_BUSCA_PARAMS
                    SELECT  Nome_Parametro, Tipo_Especifico, Indice
                    FROM    #PROC_PARAMS
           
            WHILE EXISTS (SELECT Indice FROM #PROC_BUSCA_PARAMS)
                BEGIN
           
                    -- Como estes 2 selects logo abaixo passarão às variáveis os valores da última
                    -- linha, eles são feitos ao contrário (Indice decrescente), para pegar os valores
                    -- na ordem correta.
                    SELECT  @Aux_Param = Nome_Parametro FROM #PROC_BUSCA_PARAMS ORDER BY Indice DESC
                    SELECT  @Aux_Tipo = Tipo_Especifico FROM #PROC_BUSCA_PARAMS ORDER BY Indice DESC
                    SELECT  @Aux_Int = Indice FROM #PROC_BUSCA_PARAMS ORDER BY Indice DESC
           
                    PRINT  'Procurando no código pelo parâmetro: ' + @Aux_Param + ' ' + @Aux_Tipo
           
                    -- Verifica se na linha onde o parâmetro atual é declarado aparece um sinal de igual.
                    -- Se aparecer, entende-se que aquele parâmetro possui um valor default e pode ser
                    -- omitido na chamada da proc.
                    IF EXISTS (SELECT Codigo FROM #PROC_CODE WHERE Codigo LIKE '%' + @Aux_Param + '%' + @Aux_Tipo + '%=%')
                        BEGIN
                            PRINT   'Opcional: SIM'
                            UPDATE  #PROC_PARAMS SET Opcional = 1 WHERE Indice = @Aux_Int
                        END
                    ELSE
                        BEGIN
                            PRINT   'Opcional: NAO'
                        END
           
                    -- Depois que já utilizou um registro de #PROC_BUSCA_PARAMS, apaga-o da tabela.
                    DELETE  #PROC_BUSCA_PARAMS WHERE Indice IN ( SELECT TOP 1 Indice FROM #PROC_BUSCA_PARAMS)
           
                    PRINT   ''
           
                END

    /* *********************************************** */
    /* RETORNA 2 TABELAS: O RESUMO DA PROC ANALISADA E */
    /* O CABEÇALHO DA MESMA                            */
    /* *********************************************** */

            -- Retorno 1
            SELECT  Nome_Parametro,
                    Tipo_Especifico,
                    Tipo_Primitivo,
                    Tamanho,
                    Digitos_Int,
                    Digitos_Dec,
                    Opcional,
                    Ordem
            FROM #PROC_PARAMS

            -- Retorno 2
            SELECT Declaracao = Codigo FROM #PROC_CODE


    /* ************************* */
    /* APAGA TABELAS TEMPORÁRIAS */
    /* ************************* */

            DROP TABLE #PROC_BUSCA_PARAMS
            DROP TABLE #PROC_PARAMS
            DROP TABLE #PROC_CODE


    RETURN

    sexta-feira, 23 de fevereiro de 2007 12:40