Как обнаружить разрыв интерфейса между хранимой процедурой

63
4

Я работаю над большим проектом с большим количеством хранимых процедур. Я пришел в следующую ситуацию, когда разработчик изменил аргументы хранимой процедуры, вызванной другой хранимой процедурой.
К сожалению, ничто не мешает 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

спросил(а) 2021-01-25T18:33:29+03:00 4 месяца, 3 недели назад
1
Решение
88

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 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

ответил(а) 2021-01-25T18:33:29+03:00 4 месяца, 3 недели назад
46

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


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

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

ответил(а) 2021-01-25T18:33:29+03:00 4 месяца, 3 недели назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема