¿Número de línea de impresión SQL en comentario del procedimiento almacenado creado dinámicamente?

StackOverflow https://stackoverflow.com/questions/19850270

Pregunta

He escrito un script que tiene varios miles de líneas que estoy usando para generar algunos procedimientos almacenados dinámicamente.

Quiero hacer referencia al script que generó los procedimientos almacenados en los comentarios en los procedimientos almacenados, y me gustaría poder consultar la línea en el archivo de script insertando el número de línea del archivo de script en los comentarios en el procedimiento almacenado expediente.

Entonces, por ejemplo, si @@ line_number dio el número de línea que quiero en el código a continuación, entonces @@ line_number debería ser 5

1| declare @job varchar(max)
2| SET @job = '/* this is generated dynamicly by _______  */'
3| SET @job = @job + 'SELECT *' + CHAR(10)
4| SET @job = @job + 'FROM ' + @Table_Name + CHAR(10)
5| SET @job = @job + '/* ' + @@line_number + ' */'
¿Fue útil?

Solución

Puede usar Try / Catch con un error forzado ya que el bloque de captura puede devolver el número de línea en el que se produjo el error a través de la función ERROR_LINE (). La construcción completa, formateada para legibilidad, es:

BEGIN TRY
    ;THROW 50000, 'Line#', 1 -- all 3 values are arbitrary, but required
END TRY
BEGIN CATCH
    SET @LineNumber = ERROR_LINE()
END CATCH

Ahora, para que la variable @LinEnumber se complete con el número de línea en el que se está estableciendo, puede reducir esa construcción a una sola línea de la siguiente manera:

BEGIN TRY;THROW 50000,'',1;END TRY BEGIN CATCH;SET @Line=ERROR_LINE();END CATCH

Aquí hay un ejemplo completo de que funciona:

SET ANSI_NULLS ON
SET NOCOUNT ON
GO
-- Line #1 (of current batch, not of the entire script if GOs are used)

DECLARE @CRLF NCHAR(2) = NCHAR(13) + NCHAR(10),
        @SQL1 NVARCHAR(MAX) = '',
        @SQL2 NVARCHAR(MAX) = '', -- Line #5
        @Line INT = -1 -- default to an invalid line #

SET @SQL1 += N'/********************' + @CRLF
SET @SQL1 += N' *' + @CRLF
SET @SQL1 += N' * Test Auto-' + @CRLF -- Line #10
SET @SQL1 += N' * Generated Proc 1' + @CRLF
BEGIN TRY;THROW 50000,'',1;END TRY BEGIN CATCH;SET @Line=ERROR_LINE();END CATCH
SET @SQL1 += N' * Line #:' + CONVERT(NVARCHAR(10), @Line) + @CRLF
SET @SQL1 += N' *' + @CRLF
SET @SQL1 += N' ********************/' + @CRLF -- Line #15

-- more code here

SET @SQL2 += N'/********************' + @CRLF
SET @SQL2 += N' *' + @CRLF -- Line #20
SET @SQL2 += N' * Test Auto-' + @CRLF
SET @SQL2 += N' * Generated Proc 2' + @CRLF
BEGIN TRY;THROW 50000,'',1;END TRY BEGIN CATCH;SET @Line=ERROR_LINE();END CATCH
SET @SQL2 += N' * Line #:' + CONVERT(NVARCHAR(10), @Line) + @CRLF
SET @SQL2 += N' *' + @CRLF -- Line #25
SET @SQL2 += N' ********************/' + @CRLF

PRINT @SQL1
PRINT @SQL2
GO

Los números de línea devueltos para Proc 1 y Proc 2 son 12 y 23 respectivamente, lo que es correcto para ambos.

Tenga en cuenta que el comando de lanzamiento comenzó en SQL Server 2012. Si está utilizando SQL Server 2005, 2008 o 2008 R2, entonces debe usar la función RaisError () en lugar de lanzar.

Otros consejos

Cambié Respuesta de Solomonrutzky Un poco para obtener es trabajar en versiones de SQL Server antes de 2012:

DECLARE @Line INT
SET @Line = 0 BEGIN TRY RAISERROR ('Line#', 11, 1)WITH NOWAIT   END TRY BEGIN CATCH SET @Line=ERROR_LINE() END CATCH

PRINT('/* testing ... I messed up somewhere near line: ' + CONVERT(varchar(10), ISNULL(@Line, 0)) + ' */')

No he encontrado una función incorporada para devolver el número de línea actual, por lo que he comenzado a funcionar para encontrar el número de línea para mí.

Si recibo el texto de la consulta de ejecución actual en la parte superior y declaro alguna variable, y luego copio y paso la llamada de función y el código de incremento @LineCounter, puedo obtener el número de línea actual.

    DECLARE @var1 NVARCHAR(MAX) 
    SELECT @var1 = sqltext.TEXT
    FROM sys.dm_exec_requests req
    CROSS APPLY sys.dm_exec_sql_text(sql_handle) AS sqltext
    WHERE req.session_id = @@SPID
    DECLARE @LineCounter int
    SET @LineCounter = 0
    DECLARE @Current_Line_Number int
    SET @Current_Line_Number = 0
SET @LineCounter = @LineCounter + 1
SELECT @Current_Line_Number = [MSMS].[dbo].[ReturnLineNumber] (@var1, @LineCounter)
PRINT @Current_Line_Number

Esta es la función

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- =============================================
-- Author:      James J
-- Create date: 11/11/2013
-- Description: Function to return the line number for 
-- where the query was called from when passed the query 
-- an the count of the times it has already been used.
-- =============================================
ALTER FUNCTION ReturnLineNumber 
(
    @CurrentQuery nvarchar(max), 
    @Count  int
)
RETURNS int
AS
BEGIN
    DECLARE @var1 NVARCHAR(MAX) 
    DECLARE @functionName nvarchar(30)
    SET @functionName = 'ReturnLineNumber'
    SET @var1 = @CurrentQuery

    DECLARE @LineCount int
    SET @LineCount = 0

    IF (CHARINDEX(CHAR(13), @var1) > 0)
    BEGIN
        DECLARE @queryString nvarchar(max)
        SET @queryString = @var1
        DECLARE @LineIndex int
        SET @LineIndex = 1
        DECLARE @LineLength int
        DECLARE @linestring nvarchar(max)
        DECLARE @functioncount int
        SET @functioncount = 0
        WHILE (@LineIndex > 0)
        BEGIN
            SET @LineIndex = CHARINDEX(CHAR(13), @queryString)
            SET @LineLength = LEN(@queryString) - CHARINDEX(CHAR(13), @queryString)
            SET @linestring = SUBSTRING(@queryString, 0, @LineIndex + 1)
            SET @queryString = SUBSTRING(@queryString, @LineIndex + 1, @LineLength)
            SET @LineCount = @LineCount + 1
            IF (CHARINDEX(@functionName, @linestring) > 0)
            BEGIN
                SET @functioncount = @functioncount + 1
                IF (@functioncount = @Count)
                BEGIN
                    RETURN @LineCount
                END
            END
        END
    END
    RETURN 0
END
GO

Esta no es una excelente manera de obtener el número de línea y probablemente debería agregar algunas verificaciones más para asegurarme de que no haya comentado llamadas de funciones, pero esto es lo más cercano que tengo por el momento.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top