একটি নির্বাচন যোগ করার সময় স্ব-রেফারেন্সিং স্কেলার ফাংশন নেস্টিং স্তর অতিক্রম করে


24

উদ্দেশ্য

স্ব-রেফারেন্সিং ফাংশনের পরীক্ষার উদাহরণ তৈরি করার চেষ্টা করার সময়, একটি সংস্করণ ব্যর্থ হয় এবং অন্য একটি সফল হয়।

SELECTউভয়ের জন্য পৃথক সম্পাদন পরিকল্পনার ফলে ফাংশন বডিটিতে যুক্ত হওয়া কেবলমাত্র তফাত ।


যে ফাংশনটি কাজ করে

CREATE FUNCTION dbo.test5(@i int)
RETURNS INT
AS 
BEGIN
RETURN(
SELECT TOP 1
CASE 
WHEN @i = 1 THEN 1
WHEN @i = 2 THEN 2
WHEN @i = 3 THEN  dbo.test5(1) + dbo.test5(2)
END
)
END;

ফাংশন কলিং

SELECT dbo.test5(3);

রিটার্নস

(No column name)
3

যে ফাংশনটি কাজ করে না

CREATE FUNCTION dbo.test6(@i int)
RETURNS INT
AS 
BEGIN
RETURN(
SELECT TOP 1
CASE 
WHEN @i = 1 THEN 1
WHEN @i = 2 THEN 2
WHEN @i = 3 THEN (SELECT dbo.test6(1) + dbo.test6(2))
END
)END;

ফাংশন কলিং

SELECT dbo.test6(3);

অথবা

SELECT dbo.test6(2);

ত্রুটি ফলাফল

সর্বাধিক সঞ্চিত প্রক্রিয়া, ফাংশন, ট্রিগার, বা দেখুন নেস্টিং স্তরটি ছাড়িয়ে গেছে (সীমা 32)।

কারণ অনুমান করা

ব্যর্থ ফাংশন, কলিংয়ের আনুমানিক পরিকল্পনার জন্য একটি অতিরিক্ত কম্পিউট স্কেলার রয়েছে

<ColumnReference Column="Expr1002" />
<ScalarOperator ScalarString="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">

এবং expr1000 হচ্ছে

<ColumnReference Column="Expr1000" />
<ScalarOperator ScalarString="[dbo].[test6]((1))+[dbo].[test6]((2))">

যা পুনরাবৃত্তির উল্লেখগুলি 32 এর বেশি রেফারেন্স ব্যাখ্যা করতে পারে।

আসল প্রশ্ন

যোগ SELECTতোলে ফাংশন কল নিজেই বহুবার, একটি অবিরাম লুপ ফলে, কিন্তু কেন একটি যোগ করা হয় SELECTএই ফলাফল দেবার?


অতিরিক্ত তথ্য

আনুমানিক বাস্তবায়ন পরিকল্পনা

ডিবি <> বেহালার

Build version:
14.0.3045.24

100 এবং 140 এর সামঞ্জস্যের_পরে পরীক্ষা করা হয়েছে

উত্তর:


26

এটি প্রজেক্টের নরমালাইজেশনের একটি বাগ , একটি অ-নিরস্তকরণমূলক ক্রিয়াকলাপের সাথে কেস এক্সপ্রেশনটির ভিতরে সাব-কোয়েরি ব্যবহার করে উদ্ভাসিত।

ব্যাখ্যা করার জন্য, আমাদের সামনে দুটি জিনিস নোট করতে হবে:

  1. এসকিউএল সার্ভার সরাসরি সাবকিউরিগুলি চালাতে পারে না, তাই এগুলি সর্বদা তালিকাভুক্ত বা কোনও প্রয়োগে রূপান্তরিত হয় ।
  2. এর শব্দার্থবিজ্ঞানগুলি CASEএমন যে একটি ধারাটি THENযদি WHENসত্যটি ফিরে আসে তবেই একটি অভিব্যক্তিটি মূল্যায়ন করা উচিত ।

সমস্যাযুক্ত ক্ষেত্রে প্রবর্তিত (তুচ্ছ) সাব-কোয়েরি ফলস্বরূপ একটি প্রয়োগ অপারেটর (নেস্টেড লুপস যোগ দেয়) ফলাফল। দ্বিতীয় প্রয়োজনীয়তা পূরণের জন্য, এসকিউএল সার্ভার প্রাথমিকভাবে dbo.test6(1) + dbo.test6(2)প্রয়োগের অভ্যন্তরীণ দিকে প্রকাশ করে:

হাইলাইট গণনা স্কেলার

[Expr1000] = Scalar Operator([dbo].[test6]((1))+[dbo].[test6]((2)))

... যোগদানের উপর CASEএকটি পাস- থ্রোক দ্বারা সম্মানিত শব্দার্থবিজ্ঞানের সাথে:

[@i]=(1) OR [@i]=(2) OR IsFalseOrNull [@i]=(3)

লুপটির অভ্যন্তরীণ দিকটি কেবল তখনই মূল্যায়ন করা হয় যদি পাস-থ্রু শর্তটি মিথ্যা (অর্থ @i = 3) এর কাছে মূল্যায়ন করে । এটি এখন পর্যন্ত সব ঠিক আছে। কম্পিউট স্কালে নিম্নলিখিত নেস্টেড loops যোগদানের এছাড়াও সম্মান CASEসঠিকভাবে শব্দার্থবিদ্যা:

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

সমস্যাটি হ'ল ক্যোয়ারী সংকলনের প্রকল্পের স্বাভাবিককরণের স্তরটি Expr1000এটি নিরবিচ্ছিন্নভাবে দেখে এবং নির্ধারণ করে যে এটি নিরাপদ হবে ( বর্ণনাকারী: এটি নয় ) এটিকে লুপের বাইরে নিয়ে যেতে হবে:

সরানো প্রকল্প

[Expr1000] = Scalar Operator([dbo].[test6]((1))+[dbo].[test6]((2)))

এটি পাস- থ্রো প্রিডিকেট দ্বারা প্রয়োগ করা শব্দার্থবিধি ভেঙে দেয়, সুতরাং ফাংশনটি কখন হওয়া উচিত নয় তা মূল্যায়ন করা হয় এবং অসীম লুপ ফলাফল হয়।

আপনার এই বাগটি রিপোর্ট করা উচিত। একটি কর্মসংস্থান হ'ল অভিব্যক্তিটিকে এর সাথে সম্পর্কিত করে (যেমন @iঅভিব্যক্তিতে অন্তর্ভুক্ত করে) প্রয়োগের বাইরে সরিয়ে নেওয়া রোধ করা তবে এটি অবশ্যই একটি হ্যাক। প্রকল্পের সাধারণীকরণকে অক্ষম করার একটি উপায় আছে, তবে আমাকে এটি সর্বজনীনভাবে ভাগ না করার জন্য আগেই জিজ্ঞাসা করা হয়েছিল, তাই আমি তা করব না।

স্কেলার ফাংশনটি ইনলাইন করা অবস্থায় এসকিউএল সার্ভার 2019-এ এই সমস্যাটি দেখা দেয় না , কারণ ইনলাইনিং লজিকগুলি পার্সড ট্রিটিতে সরাসরি পরিচালনা করে (প্রকল্পের স্বাভাবিককরণের আগে ভাল)। প্রশ্নটিতে সরল যুক্তি অনার্সিং-এ অন্তর্নিহিত যুক্তি দ্বারা সহজ করা যেতে পারে:

[Expr1019] = (Scalar Operator((1)))
[Expr1045] = Scalar Operator(CONVERT_IMPLICIT(int,CONVERT_IMPLICIT(int,[Expr1019],0)+(2),0))

... যা ফেরত 3।

মূল সমস্যাটি চিত্রিত করার আরেকটি উপায় হ'ল:

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

২০০৮ R2 থেকে 2019 সিটিপি 3.0 পর্যন্ত সমস্ত সংস্করণের সর্বশেষতম বিল্ডগুলিতে পুনরুত্পাদন করে।

মার্টিন স্মিথের দেওয়া আরও একটি উদাহরণ (কোনও স্কেলারের কাজ ছাড়াই) :

SELECT IIF(@@TRANCOUNT >= 0, 1, (SELECT CRYPT_GEN_RANDOM(4)/ 0))

এটিতে প্রয়োজনীয় সমস্ত মূল উপাদান রয়েছে:

  • CASE(অভ্যন্তরীণভাবে হিসাবে বাস্তবায়িত ScaOp_IIF)
  • একটি অ-বিবাদী ফাংশন ( CRYPT_GEN_RANDOM)
  • শাখায় একটি সাবকোয়ারি যা কার্যকর করা উচিত নয় ( (SELECT ...))

* কঠোরভাবে, উপরোক্ত রূপান্তরটি এখনও সঠিক হতে পারে যদি মূল্যায়ন Expr1000সঠিকভাবে পিছিয়ে দেওয়া হয়, কারণ এটি কেবল নিরাপদ নির্মাণ দ্বারা রেফারেন্স করা হয়:

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

... তবে এর জন্য একটি অভ্যন্তরীণ ফোর্সআর্ডার পতাকা প্রয়োজন (কোয়েরি ইঙ্গিত নয়), যা সেটও করা হয়নি। যে কোনও ক্ষেত্রে, প্রকল্পের নরমালাইজেশন দ্বারা প্রয়োগ করা যুক্তির বাস্তবায়নটি ভুল বা অসম্পূর্ণ।

এসকিউএল সার্ভারের জন্য অ্যাজুরে প্রতিক্রিয়া সাইটে বাগ রিপোর্ট

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.