সন্নিবিষ্ট-এক্সিকিউটি ব্লক ব্যবহার করে সঞ্চিত পদ্ধতিতে ব্যতিক্রমগুলি পরিচালনা করা


10

আমার একটি সঞ্চিত প্রক্রিয়া রয়েছে যা একটি ইনসার্ট-এক্সিকিউশন ব্লকে ডাকা হয়:

insert into @t
    exec('test')

আমি কীভাবে সঞ্চিত পদ্ধতিতে উত্পন্ন ব্যতিক্রমগুলি পরিচালনা করতে পারি এবং এখনও প্রক্রিয়া চালিয়ে যেতে পারি?

নিম্নলিখিত কোডটি সমস্যার চিত্রিত করে। আমি যা করতে চাই তা হল অভ্যন্তরীণ exec()কলটির সাফল্য বা ব্যর্থতার উপর নির্ভর করে 0 বা -1 ফিরিয়ে আনা :

alter procedure test -- or create
as
begin try
    declare @retval int;
    -- This code assumes that PrintMax exists already so this generates an error
    exec('create procedure PrintMax as begin print ''hello world'' end;')
    set @retval = 0;
    select @retval;
    return(@retval);
end try
begin catch
    -- if @@TRANCOUNT > 0 commit;
    print ERROR_MESSAGE();
    set @retval = -1;
    select @retval;
    return(@retval);
end catch;
go

declare @t table (i int);

insert into @t
    exec('test');

select *
from @t;

আমার সমস্যা হচ্ছে return(-1)। সাফল্যের পথ ঠিক আছে।

যদি আমি সঞ্চিত পদ্ধতিতে চেষ্টা / ধরার ব্লকটি ছেড়ে যাই তবে ত্রুটিটি উত্থাপিত হয় এবং সন্নিবেশ ব্যর্থ হয়। যাইহোক, আমি যা করতে চাই তা হ'ল ত্রুটিটি পরিচালনা করা এবং একটি ভাল মান ফিরিয়ে দেওয়া।

কোডটি বার্তাটি দেয়:

Msg 3930, Level 16, State 1, Line 6
The current transaction cannot be committed and cannot support operations that write to the log file. Roll back the transaction.

এটি সম্ভবত আমি সবচেয়ে খারাপ ত্রুটির বার্তা পেয়েছি। এর সত্যিকারের অর্থ মনে হচ্ছে "আপনি নেস্টেড লেনদেনে কোনও ত্রুটি পরিচালনা করেন নি"।

আমি যদি এটিতে রাখি if @@TRANCOUNT > 0, তবে আমি বার্তাটি পাই:

Msg 3916, Level 16, State 0, Procedure gordontest, Line 7
Cannot use the COMMIT statement within an INSERT-EXEC statement unless BEGIN TRANSACTION is used first.

আমি লেনদেনের স্টেটমেন্ট / কমিটমেন্ট স্টেটমেন্ট দিয়ে প্রায় খেলতে চেষ্টা করেছি, কিন্তু কিছুই কার্যকর বলে মনে হচ্ছে না।

সুতরাং, সামগ্রিক লেনদেন বাতিল না করে আমি কীভাবে আমার সঞ্চিত পদ্ধতিতে হ্যান্ডেল ত্রুটি রাখতে পারি?

মার্টিনের জবাবে সম্পাদনা করুন:

আসল কলিং কোডটি হ'ল:

        declare @RetvalTable table (retval int);

        set @retval = -1;

        insert into @RetvalTable
            exec('

@retval int ঘোষণা করুন; exec @retval = '+ @ ক্যোয়ারী +'; @ রিটাল 'নির্বাচন করুন);

        select @retval = retval from @RetvalTable;

@queryসঞ্চিত পদ্ধতি কলটি কোথায় । লক্ষ্যটি হ'ল সঞ্চিত পদ্ধতি থেকে রিটার্নের মান পাওয়া। যদি এটি সম্ভব হয় insert(বা, আরও সুনির্দিষ্টভাবে, কোনও লেনদেন শুরু না করে), এটি দুর্দান্ত।

আমি কোনও টেবিলে মান সংরক্ষণ করতে সাধারণভাবে সঞ্চিত প্রক্রিয়াগুলিকে সংশোধন করতে পারি না, কারণ তাদের মধ্যে অনেকগুলি রয়েছে। এক তাদের ব্যর্থ হচ্ছে, এবং আমি যে পরিবর্তন করতে পারেন। আমার বর্তমান সেরা সমাধানটি এরকম:

if (@StoredProcedure = 'sp_rep__post') -- causing me a problem
begin
    exec @retval = sp_rep__post;
end;
else
begin
    -- the code I'm using now
end;

আপনি টেবিলের পরিবর্তনশীলটিতে কী সন্নিবেশ করানোর চেষ্টা করছেন? রিটার্ন মানটি যাইহোক সেখানে sertedোকানো হয় না। declare @t table (i int);declare @RC int;exec @RC = test;insert into @t values (@RC);select * from @t;ঠিকভাবে কাজ করে.
মার্টিন স্মিথ

@ মার্টিনস্মিথ । । কোডটি সত্যই যেভাবে কাজ করে তা select @retval; return @retvalশেষের মতো। আপনি যদি ডায়নামিক স্টোরেজ পদ্ধতি কল থেকে রিটার্ন মান পাওয়ার অন্য কোনও উপায় জানেন তবে আমি তা জানতে আগ্রহী।
গর্ডন লিনফ

ওয়েল অন্য উপায় হবেDECLARE @RC INT;EXEC sp_executesql N'EXEC @RC = test', N'@RC INT OUTPUT', @RC = @RC OUTPUT;insert into @t VALUES (@RC)
মার্টিন স্মিথ

@ মার্টিনস্মিথ । । আমি মনে করি এটি কার্যকর হবে। আমরা অর্ধ দিন হার্ডওয়্যার ত্রুটি ("লগ ফাইলটিতে লেখা অপারেশনগুলিকে সমর্থন করতে পারি না" একটি হার্ডওয়্যার ব্যর্থতার মতো মনে হচ্ছে) এবং কোডটি সঠিকভাবে পাওয়ার জন্য গত কয়েক ঘন্টা ব্যয় করে কাটিয়েছি। পরিবর্তনশীল প্রতিস্থাপন একটি দুর্দান্ত উত্তর।
গর্ডন লিনফ

উত্তর:


13

বিবৃতিটির EXECঅংশে ত্রুটিটি INSERT-EXECআপনার লেনদেনকে একটি ডুমড অবস্থায় ফেলে দিচ্ছে ।

যদি আপনি ব্লকে PRINTবাইরে XACT_STATE()যান তবে CATCHএটি সেট করা আছে -1

সমস্ত ত্রুটি রাষ্ট্রকে এটি সেট করবে না। নিম্নলিখিত চেক সীমাবদ্ধতা ত্রুটি ক্যাচ ব্লক হয়ে যায় এবং INSERTসফল হয়।

ALTER PROCEDURE test -- or create
AS
  BEGIN try
      DECLARE @retval INT;

      DECLARE @t TABLE(x INT CHECK (x = 0))

      INSERT INTO @t
      VALUES      (1)

      SET @retval = 0;

      SELECT @retval;

      RETURN( @retval );
  END try

  BEGIN catch
      PRINT XACT_STATE()

      PRINT ERROR_MESSAGE();

      SET @retval = -1;

      SELECT @retval;

      RETURN( @retval );
  END catch; 

এটি CATCHব্লকে যুক্ত করা হচ্ছে

 IF (XACT_STATE()) = -1
BEGIN
    ROLLBACK TRANSACTION;
END;

সাহায্য করে না। এটি ত্রুটি দেয়

ইনসার্ট-এক্সেক স্টেটমেন্টের মধ্যে রোলব্যাক স্টেটমেন্ট ব্যবহার করতে পারবেন না।

আমি মনে করি না যে এইরকম ত্রুটি হয়ে যাওয়ার পরে পুনরুদ্ধারের কোনও উপায় আছে। আপনার নির্দিষ্ট ব্যবহারের ক্ষেত্রে তবে আপনার প্রয়োজন INSERT ... EXECনেই। আপনি একটি স্কেলার ভেরিয়েবলের জন্য রিটার্ন মান নির্ধারণ করতে পারেন তারপরে এটি একটি পৃথক স্টেটমেন্টে সন্নিবেশ করান।

DECLARE @RC INT;

EXEC sp_executesql
  N'EXEC @RC = test',
  N'@RC INT OUTPUT',
  @RC = @RC OUTPUT;

INSERT INTO @t
VALUES      (@RC) 

অথবা অবশ্যই আপনি তথাকথিত সঞ্চিত প্রক্রিয়াটিকে পুনর্গঠন করতে পারেন যাতে এটি ত্রুটিটি একেবারেই বাড়ায় না।

DECLARE @RetVal INT = -1

IF OBJECT_ID('PrintMax', 'P') IS NULL
  BEGIN
      EXEC('create procedure PrintMax as begin print ''hello world'' end;')

      SET @RetVal = 0
  END

SELECT @RetVal;

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