在QA中通过手动用户测试意识到存在代码错误,经过调查,这是一个明显的错误。
CREATE PROCEDURE ProcedureA
@A INT
AS SELECT 1
GO
CREATE PROCEDURE ProcedureB
AS EXEC ProcedureA @B = 0
此外,手动执行这些CREATE
语句不会引发任何错误。
另一个例子
CREATE VIEW VW_MyTestView AS
SELECT Column1 = 0
GO
CREATE PROCEDURE MyTestProcedure AS
SELECT Column1
FROM VW_MyTestView
GO
ALTER VIEW VW_MyTestView AS
SELECT Column2 = 0
修改对象时,它不会验证依赖项。
另一个骇人听闻的情况是FROM
子句中列数不等的语句INSERT
如下所示:
INSERT INTO MyTable(TheOnlyColumn)
SELECT
Column1 = ...
,Column2 = ...
,Column3 = ...
至少在更改/创建存储过程时会发现此问题。
另一个例子
CREATE PROCEDURE MyProcedure
@MyFlag BIT = 0
AS BEGIN
IF @MyFlag = 1
BEGIN
DECLARE @MyImportantVariable DATE = GETDATE()
END
EXEC MyOtherProcedureThatNeedsAnImportantValue
@MyImportantParameter = @MyImportantVariable
END
没有错误,当值@MyImportantVariable
被引用时,它将被NULL
,而不是遵循任何声明。在这种情况下,我实际上更希望抛出错误,因为调试一个令人惊讶的NULL
值更加困难。
另一个类似于#1的例子,在过去一年中幸存了数千个门控TFS构建后,它让我脸上出现了一个鸡蛋:
CREATE PROCEDURE MyProcedure
@MyRequiredVariable INT--has no default
AS BEGIN
...
END
GO
EXEC MyProcedure--omits required parameter
为什么 MSBuild 进程没有捕获这样的东西,这显然是无效的,有没有办法为此类引用错误添加验证?我可以理解前两种情况在发布更改时是必要的,因为否则您将遇到无法刷新相互引用的定义的第 22 条军规,但第三种情况是没有意义的,永远无法接受,第四种情况甚至永远不会用 C# 这样的语言编译。
这也破坏了我们的门控签入构建验证过程。
发生这种情况是因为 SQL Server 存储过程的Deferred Name Resolution and Compilation
属性。
如果它不是存储过程、函数、表或视图等,那么它在编译时就会出错。
但是,SQL Server 存储过程仅在创建时检查语法准确性,并且存储过程的定义按原样存储。
它仅在运行时,在第一次执行对象时 检查过程引用,如果缺少任何内容,该过程将引发错误。