Как обнаружить разрыв интерфейса между хранимой процедурой - PullRequest
1 голос
/ 22 февраля 2011

Я работаю над большим проектом с большим количеством хранимых процедур. Я попал в следующую ситуацию, когда разработчик изменил аргументы хранимой процедуры, которая была вызвана другой хранимой процедурой. К сожалению, ничто не мешает завершить ALTER PROC.

Есть ли способ выполнить эти проверки впоследствии? Каковы рекомендации, чтобы избежать подобных проблем?

Вот пример кода для воспроизведения этого поведения:

CREATE PROC Test1 @arg1 int
AS
BEGIN
PRINT CONVERT(varchar(32), @arg1)
END
GO

CREATE PROC Test2 @arg1 int
AS
BEGIN
DECLARE @arg int;
SET @arg = @arg1+1;
EXEC Test1 @arg;
END
GO

EXEC Test2 1;
GO

ALTER PROC Test1 @arg1 int, @arg2 int AS
BEGIN
PRINT CONVERT(varchar(32), @arg1)
PRINT CONVERT(varchar(32), @arg2)
END
GO

EXEC Test2 1;
GO

DROP PROC Test2
DROP PROC Test1
GO

Ответы [ 2 ]

3 голосов
/ 22 февраля 2011

Sql server 2005 имеет системное представление sys.sql_dependencies , которое отслеживает зависимости. К сожалению, это не так уж и надежно (подробнее см. ответ ). Oracle, однако, намного лучше в этом отношении. Таким образом, вы могли бы переключиться. Есть также сторонний поставщик, Redgate, у которого есть Sql Dependency Tracker . Сам никогда не проверял, но есть пробная версия.

У меня та же проблема, поэтому я реализовал решение моего бедняка, создав хранимую процедуру, которая может искать строки во всех хранимых процедурах и представлениях в текущей базе данных. При поиске по имени измененной хранимой процедуры я могу (надеюсь) найти вызовы EXEC.

Я использовал это на SQL Server 2000 и 2008, поэтому, вероятно, он также работает и в 2005 году. (Примечание: @word1, @word2 и т. Д. Должны присутствовать, но это можно легко изменить в последнем SELECT, если вы есть разные потребности.)

CREATE PROCEDURE [dbo].[findWordsInStoredProceduresViews]
@word1 nvarchar(4000) = null,
@word2 nvarchar(4000) = null,
@word3 nvarchar(4000) = null,
@word4 nvarchar(4000) = null,
@word5 nvarchar(4000) = null
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    -- create temp table 
    create table #temp
    ( 
        id int identity(1,1),
        Proc_id INT, 
        Proc_Name SYSNAME, 
        Definition NTEXT 
    ) 

    -- get the names of the procedures that meet our criteria 
    INSERT #temp(Proc_id, Proc_Name) 
        SELECT id, OBJECT_NAME(id) 
            FROM syscomments 
            WHERE OBJECTPROPERTY(id, 'IsProcedure') = 1 or
                  OBJECTPROPERTY(id, 'IsView') = 1 
            GROUP BY id, OBJECT_NAME(id) 

    -- initialize the NTEXT column so there is a pointer 
    UPDATE #temp SET Definition = '' 

    -- declare local variables 
    DECLARE  
        @txtPval binary(16),  
        @txtPidx INT, 
        @curText NVARCHAR(4000), 
        @counterId int,
        @maxCounterId int,
        @counterIdInner int,
        @maxCounterIdInner int

    -- set up a double while loop to get the data from syscomments

    select @maxCounterId = max(id)
    from #temp t

    create table #tempInner  
    (
        id int identity(1,1),
        curName SYSNAME, 
        curtext ntext
    ) 


    set @counterId = 0

    WHILE (@counterId < @maxCounterId) 
    BEGIN 
        set @counterId = @counterId + 1

        insert into #tempInner(curName, curtext)
        SELECT OBJECT_NAME(s.id), text 
        FROM syscomments s 
        INNER JOIN #temp t 
        ON s.id = t.Proc_id 
        WHERE t.id = @counterid
        ORDER BY s.id, colid

        select @maxCounterIdInner = max(id)
        from #tempInner t

        set @counterIdInner = 0
        while (@counterIdInner < @maxCounterIdInner)
        begin
            set @counterIdInner = @counterIdInner + 1

            -- get the pointer for the current procedure name / colid 
            SELECT @txtPval = TEXTPTR(Definition) 
                FROM #temp
                WHERE id = @counterId

            -- find out where to append the #temp table's value 
            SELECT @txtPidx = DATALENGTH(Definition)/2 
                FROM #temp 
                WHERE id = @counterId

            select @curText = curtext
            from #tempInner
            where id = @counterIdInner

            -- apply the append of the current 8KB chunk 
            UPDATETEXT #temp.definition @txtPval @txtPidx 0 @curtext 
        end

        truncate table #tempInner
    END 

    -- check our filter 
    SELECT Proc_Name, Definition 
        FROM #temp t
        WHERE (@word1 is null or definition LIKE '%' + @word1 + '%') AND
              (@word2 is null or definition LIKE '%' + @word2 + '%') AND
              (@word3 is null or definition LIKE '%' + @word3 + '%') AND
              (@word4 is null or definition LIKE '%' + @word4 + '%') AND
              (@word5 is null or definition LIKE '%' + @word5 + '%') 
        ORDER BY Proc_Name

    -- clean up 
    DROP TABLE #temp 
    DROP TABLE #tempInner
END
0 голосов
/ 22 февраля 2011

Вы можете использовать sp_refreshsqlmodule, чтобы попытаться повторно проверить SP (это также обновляет зависимости), но он не будет проверять этот конкретный сценарий с параметрами на уровне вызывающего (он будет проверять такие вещи, как недопустимые столбцы в таблицах и представлениях).

http://www.mssqltips.com/tip.asp?tip=1294 имеет ряд методов, включая sp_depends

Информация о зависимостях хранится в метаданных SQL Server, включая столбцы / типы параметров для каждого SP и функции, но это не так.Неясно, как проверить все вызовы, но их можно найти и проверить.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...