🔥

sqlserver 2019, 2022の再起関数のバグ

2023/02/13に公開

sqlserverには自分が確認する限り、下記の再起関数のバグが存在します。

バグを公開した理由について

sqlserver 2019の時点でMSにバグレポート込みで報告したが、部署をたらい回しにされた上で、
音沙汰が無く、sqlserver 2022になってもバグが放置されていたため。

バグについて

CREATE FUNCTION dbo.factorial ( @n BIGINT )
RETURNS BIGINT
AS
BEGIN
DECLARE @ret BIGINT;

    IF @n = 0
        SET @ret = 1;
    ELSE
        SET @ret = @n * dbo.factorial( @n - 1 );
RETURN @ret;
END;
GO
select dbo.factorial(3)

上記のような再起関数を作成後、実行すると、三回目の再起でのみ
下記のエラーが発生する。

Maximum stored procedure, function, trigger, or view nesting level exceeded (limit 32).

しかし、三回目の再起以外では下記のように正しい値を返す。

select dbo.factorial(0) -- -> 1
select dbo.factorial(1) -- -> 1
select dbo.factorial(2) -- -> 2
select dbo.factorial(4) -- -> 24
...

select dbo.factorial(11) -- -> 39916800
select dbo.factorial(12) -- -> 479001600

バグの回避方法

下記のように三回目の再起のみ、
再起せずに特定の値を計算する作りにすればよい。

-- Code for avoiding bugs
CREATE FUNCTION dbo.factorial ( @n BIGINT )
RETURNS BIGINT
AS
BEGIN
DECLARE @ret BIGINT;

    IF @n = 0
        SET @ret = 1;
    -- These two lines are necessary to avoid bugs.
    ELSE IF @n = 3
        SET @ret = 6;
    ELSE
        SET @ret = @n * dbo.factorial( @n - 1 );
RETURN @ret;
END;
GO

追記

これはsqlserver2019の新機能であるスカラーUDFインライン関数のバグらしいです。

今のところはバグをよけるにはインラインの展開をOFFにするしかないみたいです。

ALTER DATABASE SCOPED CONFIGURATION SET TSQL_SCALAR_UDF_INLINING = OFF;
GO

詳しい人に教えてもらいました。

スカラー UDF のインライン化

要件の所をよく見ると
SQL Server 2019 (15.x) CU2 に制限を追加
SQL Server 2019 (15.x) CU4 に制限を追加
...
と累積更新プログラムでかなりガチャガチャ触っている所みたいですね...
他にも不具合があるのかも。

新機能の癖にsqlserver 2019, 2022もデフォルトではTSQL_SCALAR_UDF_INLININGはONになっているのが、
またいやらしい...

すでに運用に回っているシステムでない限りはとりあえずOFFにしておいた方が良いでしょう。
結局得られるメリットは速度面だけだし。

まとめ

sqlserverには他にも再起のバグあるぞ...
sqlserverで再起は使うのやめた方がよさそう
そもそもsqlserver自体に結構バグあるのかもね。

dotnetとwindowsの環境変数のバグの放置と言い、
スケジューラのバグ放置と言い、もうねぇ...
MSのバグに対する姿勢にはオコですよ...

Discussion