Sql server SQL Server 2008 R2-标量UDF导致无限循环

Sql server SQL Server 2008 R2-标量UDF导致无限循环,sql-server,sql-server-2008,tsql,pattern-matching,user-defined-functions,Sql Server,Sql Server 2008,Tsql,Pattern Matching,User Defined Functions,以下代码导致无限循环或执行速度非常慢: CREATE FUNCTION [dbo].[CleanUriPart] ( -- Add the parameters for the function here @DirtyUriPart nvarchar(200) ) RETURNS nvarchar(200) AS BEGIN; -- Declare the return variable here DECLARE @Result nvarchar(200);

以下代码导致无限循环或执行速度非常慢:

CREATE FUNCTION [dbo].[CleanUriPart] 
(
    -- Add the parameters for the function here
    @DirtyUriPart nvarchar(200)
)

RETURNS nvarchar(200)
AS
BEGIN;
    -- Declare the return variable here
    DECLARE @Result nvarchar(200);

DECLARE @i int;

SET @i = 1;

WHILE 1 = 1
BEGIN;
    SET @i = PATINDEX('%[^a-zA-Z0-9.~_-]%', @DirtyUriPart COLLATE Latin1_General_BIN);
    IF @i > 0
        SET @DirtyUriPart = STUFF(@DirtyUriPart, @i, 1, '-');
    ELSE
        BREAK;
END;

-- Add the T-SQL statements to compute the return value here
SELECT @Result = @DirtyUriPart;

-- Return the result of the function
RETURN @Result;

END;
输入/输出应如下所示:

  • “abcdef”->“abcdef”工作正常
  • “abc def”->“abc def”导致无限循环
  • “abc*def”->“abc def”导致无限循环
  • 等等

请帮忙

有没有可能@DirtyUriPart的计算结果为空?在PATINDEX函数上,如果模式或表达式为NULL,PATINDEX将返回NULL,在这种情况下,NULL将导致无限循环

SELECT PATINDEX('%[^a-]%', N'aaa-def' COLLATE Latin1_General_BIN),
       PATINDEX('%[^-a]%', N'aaa-def' COLLATE Latin1_General_BIN), 
       PATINDEX('%[^a-]%', 'aaa-def' COLLATE Latin1_General_BIN),
       PATINDEX('%[^-a]%', 'aaa-def' COLLATE Latin1_General_BIN)
返回

----------- ----------- ----------- -----------
1           5           5           5
因此,对于
varchar
数据类型,尾随的
-
被视为集合的一部分,而对于
nvarchar
则被忽略(被视为格式错误的范围,因为
a
也被忽略了?)

的BOL条目没有明确说明如何在
[]
中使用
-
将其视为集合的一部分,但有以下示例

LIKE '[-acdf]'

为了匹配
-,a、c、d或f
,我假设它需要是集合中的第一项(即
[^a-zA-Z0-9.~-]
需要更改为
[^-a-zA-Z0-9.~~-]
)。这也与我上面的测试结果相匹配。

看起来您可以通过在
PATINDEX
中将
@DirtyUriPart
转换为
VARCHAR(200)
来解决问题,这将导致破折号与类中的其他字符一起被识别:

DECLARE @DirtyUriPart nvarchar(200)='abc-def';

-- Returns 0
SELECT PATINDEX('%[^a-zA-Z0-9.~_-]%', CAST(@DirtyUriPart AS VARCHAR(200)) COLLATE Latin1_General_BIN);

-- Returns 4
SELECT PATINDEX('%[^a-zA-Z0-9.~_-]%', @DirtyUriPart COLLATE Latin1_General_BIN);

您永远不会在循环中更改
@DirtyUriPart
,因此
@i
的值在后续迭代中永远不会更改。不,这是我在恐慌和混乱我的代码。它仍然会导致无限循环。看起来可能需要将模式更改为%[^-a-zA-Z0-9.~\]%。我假设它将
-
视为范围语法的一部分,即使它没有RHS。啊,啊,这太可怕了。这就是为什么我尽量避免我不懂的东西。谢谢你的帮助。RHS是什么意思?“右手边”。我找不到任何文档说明如何处理不带LHS和RHS的
-
符号,但需要做一些测试来确认这一点。我将在IF子句中添加一个is NULL检查,以确保它在@I为NULL时中断。问题在于PATINDEX模式。你能给我一些提示吗?当你说
SELECT PATINDEX('%[^a-zA-Z0-9.~-]%,N'abc-def'COLLATE Latin1_General_BIN),PATINDEX('%[^-a-zA-Z0-9.~]',N'abc-def'COLLATE Latin1_General_BIN)返回不同的结果时,我很担心!他们会返回不同的结果,一个正确,一个不正确。。。所以是的
%[^-a-zA-Z0-9.~\]'
似乎工作正常。再次感谢你-我在一个星期天学到了很多!那么这是SQL Server 2008中的一个bug吗?@ChrisCannon-不确定RE:bug。我看不到
varchar
nvarchar
之间在行为上的差异,这在任何地方都有记录,而且绝对不是直觉上认为应该有任何差异。在SQL Server 2000和SQL Server 2012上复制。所以,如果它是一个bug,那么它就是一个长期未被发现的bug。@AaronBertrand-