Bu, proje normalleştirmesinde , deterministik olmayan bir işlevi olan bir vaka ifadesinde bir alt sorgu kullanarak ortaya çıkan bir hatadır .
Açıklamak için iki şeyi önceden not almamız gerekiyor:
- SQL Server, alt sorguları doğrudan çalıştıramaz, bu nedenle her zaman denetlenmez veya bir uygulamaya dönüştürülür .
- 'In semantiği,
CASE
bir THEN
ifadenin sadece WHEN
madde doğru döndüğünde değerlendirilmesinin gerektiği şekildedir .
Bu nedenle, sorunlu durumda ortaya çıkan (önemsiz) alt sorgu, geçerli bir işleçle sonuçlanır (iç içe döngüler birleşir). İkinci gereksinimi karşılamak için, SQL Server ilk önce ifadeyi dbo.test6(1) + dbo.test6(2)
uygulamanın iç tarafına yerleştirir:
[Expr1000] = Scalar Operator([dbo].[test6]((1))+[dbo].[test6]((2)))
... birleşimde başarılıCASE
bir belirleyici tarafından onurlandırılan anlambilim ile :
[@i]=(1) OR [@i]=(2) OR IsFalseOrNull [@i]=(3)
Döngünün iç tarafı ancak doğrudan geçiş koşulu false (anlam @i = 3
) olarak değerlendirilirse değerlendirilir . Şimdiye kadar hepsi doğru. Hesapla Scalar iç içe döngüler de onurlandırıyor katılmak aşağıdaki CASE
doğru anlambilim:
[Expr1001] = Scalar Operator(CASE WHEN [@i]=(1) THEN (1) ELSE CASE WHEN [@i]=(2) THEN (2) ELSE CASE WHEN [@i]=(3) THEN [Expr1000] ELSE NULL END END END)
Sorun, sorgu derlemesinin proje normalleştirme aşamasının Expr1000
, ilişkisiz olduğunu görmesi ve onu döngünün dışına taşımanın güvenli olacağını ( anlatıcı: değil ) belirlemesidir:
[Expr1000] = Scalar Operator([dbo].[test6]((1))+[dbo].[test6]((2)))
Bu sonları uyguladığı anlambilim * geçişkenliğindeki olması gerektiği halde işlev değerlendirilir, böylece yüklem ve sonsuz döngü sonuçları.
Bu hatayı bildirmelisin. Bir geçici çözüm, ifadenin ilişkili hale getirilmesiyle (yani @i
ifadeye dahil olmak üzere ) başvurunun dışına taşınmasını önlemektir, ancak bu bir kesintidir. Proje normalleştirmesini devre dışı bırakmanın bir yolu var, ancak daha önce halka açık olarak paylaşmamam istendi, bu yüzden yapmayacağım.
SQL Server 2019'da skaler işlevi satır içine alındığında bu sorun ortaya çıkmaz , çünkü satır içi mantık doğrudan ayrıştırılan ağaç üzerinde çalışır (proje normalizasyonundan hemen önce). Sorudaki basit mantık özyinelemeli olmayanlara yönelik mantıkla basitleştirilebilir:
[Expr1019] = (Scalar Operator((1)))
[Expr1045] = Scalar Operator(CONVERT_IMPLICIT(int,CONVERT_IMPLICIT(int,[Expr1019],0)+(2),0))
... 3 döndürür.
Çekirdek sorunu göstermek için başka bir yol:
-- Not schema bound to make it non-det
CREATE OR ALTER FUNCTION dbo.Error()
RETURNS integer
-- WITH INLINE = OFF -- SQL Server 2019 only
AS
BEGIN
RETURN 1/0;
END;
GO
DECLARE @i integer = 1;
SELECT
CASE
WHEN @i = 1 THEN 1
WHEN @i = 2 THEN 2
WHEN @i = 3 THEN (SELECT dbo.Error()) -- 'subquery'
ELSE NULL
END;
2008 R2 ile 2019 CTP 3.0 arasındaki tüm sürümlerin en son sürümlerinde çoğaltılmıştır.
Martin Smith tarafından sağlanan bir başka örnek (skaler fonksiyon olmadan) :
SELECT IIF(@@TRANCOUNT >= 0, 1, (SELECT CRYPT_GEN_RANDOM(4)/ 0))
Bu gerekli tüm temel unsurlara sahiptir:
CASE
(dahili olarak uygulandı ScaOp_IIF
)
- Deterministik olmayan bir işlev (
CRYPT_GEN_RANDOM
)
- Dalda çalıştırılmaması gereken bir alt sorgu (
(SELECT ...)
)
* Kesinlikle, değerlendirmenin Expr1000
doğru bir şekilde ertelenmesi durumunda, yalnızca güvenli yapı tarafından referans verildiği için yukarıdaki dönüşüm hala doğru olabilir :
[Expr1002] = Scalar Operator(CASE WHEN [@i]=(1) THEN (1) ELSE CASE WHEN [@i]=(2) THEN (2) ELSE CASE WHEN [@i]=(3) THEN [Expr1000] ELSE NULL END END END)
... ancak bu, ayarlanmamış bir iç ForceOrder bayrağı (sorgu ipucu değil) gerektirir . Her durumda, proje normalizasyonu tarafından uygulanan mantığın uygulanması yanlış veya eksiktir.
SQL Server için Azure Feedback sitesinde hata raporu .