লিঙ্কযুক্ত সার্ভার ত্রুটি টিআরওয়াই-ক্যাচে ধরা পড়ে না


14

আমি লিঙ্কযুক্ত সার্ভারগুলির একটি তালিকার মধ্য দিয়ে লুপ করার জন্য একটি চাকরী স্থাপন করছি এবং প্রত্যেকটির বিরুদ্ধে একটি নির্দিষ্ট কোয়েরি সম্পাদন করছি। আমি চেষ্টাটি ট্রাই-ক্যাচ ব্লকের ভিতরে সম্পাদন করার চেষ্টা করছি তাই যদি একটি নির্দিষ্ট সার্ভারে কোনও সমস্যা হয় তবে আমি এটি লগ করতে পারি তবে অন্য সার্ভারগুলির সাথে চালিয়ে যেতে পারি।

লুপের ভিতরে আমি যে ক্যোয়ারীটি সম্পাদন করছি তা দেখতে কিছুটা এমন দেখাচ্ছে:

BEGIN TRY
    SELECT *
    FROM OPENQUERY([server1], 'SELECT 1 AS c;');
END TRY
BEGIN CATCH
    SELECT ERROR_NUMBER(), ERROR_MESSAGE();
END CATCH;

PRINT 'We got past the Catch block!';

সার্ভারের সাথে সংযোগ স্থাপনে যদি সমস্যা হয় তবে কোডটি তাত্ক্ষণিকভাবে ব্যর্থ হয় এবং CATCHব্লকে স্থানান্তর করে না । যদি সার্ভারটি সংযুক্ত হয় তবে প্রকৃত ক্যোয়ারীতে একটি ত্রুটি রয়েছে, উদাহরণস্বরূপ শূন্য দ্বারা ভাগ করা, তবে এটি CATCHব্লকের দ্বারা প্রত্যাশা অনুযায়ী ধরা পড়ে ।

উদাহরণস্বরূপ, আমি একটি নামের সাথে একটি লিঙ্কযুক্ত সার্ভার তৈরি করেছি যা আমি জানি যে বিদ্যমান নেই। উপরের এক্সিকিউট করার সময় আমি কেবল এটি পাই:

OLE DB provider "SQLNCLI" for linked server "nonserver" returned message 
    "Login timeout expired".
OLE DB provider "SQLNCLI" for linked server "nonserver" returned message 
    "An error has occurred while establishing a connection to the server. 
    When connecting to SQL Server 2005, this failure may be caused by the 
    fact that under the default settings SQL Server does not allow remote
    connections.".
Msg 53, Level 16, State 1, Line 0
Named Pipes Provider: Could not open a connection to SQL Server [53].

আমি বিওএলটি পড়েছি TRY-CATCHএবং জানি যে এটি সংযোগটি ভেঙে 20+ স্তরের ত্রুটি ধরবে না তবে এটি কেস হিসাবে মনে হচ্ছে না (এটি কেবলমাত্র 16 স্তরের)।

এই ত্রুটিগুলি সঠিকভাবে ধরা পড়ছে না এমন কি কেউ জানেন?

উত্তর:


11

আপনি চেষ্টা করতে পারেন একটি জিনিস ব্যবহার করা হয় sp_testlinkedserver। আপনি OPENQUERYরানটাইম পর্যন্ত সার্ভারের নাম বৈধকরণ করতে পার্সার পিছনে স্থির করতে ডায়নামিক এসকিউএল (সর্বোচ্চটি সঠিকভাবে নির্দেশিত হিসাবে) ব্যবহার করেও জারি করতে পারেন ।

BEGIN TRY
    EXEC sp_testlinkedserver N'server1';

    EXEC sp_executesql N'SELECT * FROM OPENQUERY([server1], 
      ''SELECT 1 AS c;'');';
END TRY
BEGIN CATCH
    SELECT ERROR_NUMBER(), ERROR_MESSAGE();
END CATCH;

PRINT 'We got past the Catch block!';

এটি ছাড়াই সমানভাবে কার্যকরভাবে কাজ sp_testlinkedserverকরার পরেও, সেই পদ্ধতিটি আপনাকে সেই সার্ভারের বিরুদ্ধে কোডের পুরো গোছাটি চেষ্টা করা থেকে বিরত রাখতে কার্যকর হতে পারে ...


এছাড়াও, যেহেতু sp_testlinkedserverএটি সংকলনের সময় যদি এটি ব্যর্থ হয় তবে এটি আপনি স্থগিত করতে পারেন এবং তবুও এটি ডায়নামিক এসকিউএল ব্যবহার করে ক্যাপচার করতে পারেন:

BEGIN TRY
  EXEC master.sys.sp_executesql N'EXEC sp_testlinkedserver N''server1'';';
  ...
END TRY

6

আপনি কি এরকম কিছু চেষ্টা করেছেন?

BEGIN TRY
    DECLARE @cmd nvarchar(max);
    SET @cmd = 'SELECT * FROM OPENQUERY([server1], ''SELECT 1 AS c;'');';
    EXEC sp_executesql @cmd;
END TRY
BEGIN CATCH
    SELECT ERROR_NUMBER(), ERROR_MESSAGE();
END CATCH;

নীচের মতামত অনুসারে, এটি কাজ করে যেহেতু সংকলন-সময় ত্রুটি আর উত্পন্ন হয় না। Sp_executesql সঞ্চিত পদ্ধতির অভ্যন্তরে ত্রুটিটি রানটাইমের সময় ঘটে।


ধন্যবাদ ম্যাক্স হ্যাঁ, আমি গতিশীল এসকিউএল (এবং উপরেরটি সত্যই সঠিকভাবে কাজ করে) এর কথা ভেবেছিলাম। ত্রুটিটি ধরা পড়েনি কেন আমি আগ্রহী?
জেমসলিন

@ অ্যারোনবার্ট্র্যান্ড আপনি যদি PRINT 'Start';স্ক্রিপ্টের একেবারে শীর্ষে কোনও সাধারণ যোগ করেন তবে এটি আউটপুটে মুদ্রিত হবে, যদিও সংযোগটি ব্যর্থ হয় এবং স্ক্রিপ্টটি ত্রুটি সহ প্রস্থান করে। সুতরাং এটি একটি রানটাইম ত্রুটি ইঙ্গিত করবে না? আমি যদি ভুল বুঝি না?
জেমসলিন

গাহ, আমি যখন যুক্ত PRINTকরেছি তখনও আমার sp_testlinkedserverস্ক্রিপ্টে কল ছিল । প্রকৃতপক্ষে, এটি আমার আসল (ব্যর্থ) স্ক্রিপ্ট ব্যবহার করে মুদ্রিত হবে না। সুতরাং দেখে মনে হচ্ছে এটি আসলে একটি সংকলন-সময় ত্রুটি, যার কারণে এটি ধরা পড়ে না।
জেমসলিন

@ জেমসলিন খুব মজার, যখন আপনি কী পরামর্শ দিচ্ছেন তা নিশ্চিত করার জন্য যখন আমি তিরস্কার করতে গিয়েছিলাম, আমি sp_testlinkedserverকলটি মন্তব্য করেছি , তবে SELECTডায়নামিক এসকিউএল হিসাবে রেখে এসেছি । PRINTআপনি সার্ভার নাম সরাসরি উল্লেখ করে ঘটবে না, তাই আমি তার আগে প্রস্তাব ছিল, BEGIN TRYপ্রবেশ না হয় কারণ ত্রুটি প্রথম উত্থাপিত হয়।
অ্যারন বারট্র্যান্ড

4

তদন্তের পরে দেখে মনে হচ্ছে যে এই ত্রুটিটি ধরা পড়ছে না কারণ এটি রানটাইম ত্রুটির পরিবর্তে একটি সংকলন-সময় ত্রুটি। এটি প্রদর্শনের জন্য, নিম্নলিখিত চেষ্টা করুন:

PRINT 'Before TRY';

BEGIN TRY
    SELECT 1/0;

    SELECT *
    FROM OPENQUERY([nonserver], 'SELECT 1 AS c;');
END TRY
BEGIN CATCH
    SELECT ERROR_NUMBER(), ERROR_MESSAGE();
END CATCH;

প্রাথমিক PRINTবিবৃতি আউটপুট পায় না বা শূন্য ত্রুটি দ্বারা বিভাজন কার্যকর হয় / ধরা পড়ে না। অস্তিত্বহীন সার্ভারের সাথে সাথে স্ক্রিপ্টটি তত্ক্ষণাত ব্যর্থ হয়।


3

আমার সম্প্রতি একইরকম সমস্যা হয়েছিল যেখানে আমি ট্রাই-ক্যাচের মধ্যে থেকে একটি রিমোট পদ্ধতিটি কল করেছি এবং নকল কী (স্তরের 16 রান সময় ত্রুটি) সন্নিবেশ করার প্রচেষ্টা করার ফলে প্রক্রিয়াটি ব্যর্থ হয়েছে। ক্যাচ ব্লকটি চালিত হয়নি। আমি এই নিবন্ধে কারণটি খুঁজে পেয়েছি: https://technet.microsoft.com/en-us/library/ms191515(v=sql.105).aspx

সমাধানটি হল দূরবর্তী প্রক্রিয়াটি শুরু করার আগে কলিং পদ্ধতিতে সেট করা XACT_ABORT ON যখন XACT_ABORT ক্যাচ ব্লকে থাকে তখন প্রত্যাশার সাথে ডাকা হয়। আপনাকে সচেতন হতে হবে XACT_ABORT সেটিংটি দূরবর্তী পদ্ধতিতে প্রচার করা হয়েছে এবং এটি এর আচরণকে প্রভাবিত করতে পারে।


0
ALTER PROCEDURE dbo.LinkedServer_Status 
    @linked_server nvarchar(128),
    @exists bit OUT,
    @connected bit OUT,
    @server_datetime datetime OUT
AS
BEGIN
    SET NOCOUNT ON;
    DECLARE @server_id int;
    SELECT @server_id = server_id from sys.servers where name = @linked_server;
    IF (@@ROWCOUNT = 0)
        SELECT @exists = 0, @connected = 0, @server_datetime = null;
    ELSE BEGIN
        SELECT @exists = 1;
        BEGIN TRY
            DECLARE @TBL TABLE(server_datetime DateTime);
            DECLARE @SQL nVarChar(2048); -- MUST BE nVarChar
            SELECT @SQL =
                'SELECT server_datetime FROM OPENQUERY(['+RTRIM(@linked_server)+'], ''SELECT GETDATE() server_datetime'')'; 
            INSERT @TBL EXEC sp_executesql @SQL;
            SELECT TOP 1 @connected = 1, @server_datetime = server_datetime FROM @TBL;
        END TRY
        BEGIN CATCH
            SELECT @connected = 0, @server_datetime = null;
            SELECT ERROR_MESSAGE();
        END CATCH
    END;
END

-- now use stored procedure

SET NOCOUNT ON;

DECLARE
    @linked_server nvarchar(128),
    @exists bit,
    @connected bit,
    @server_datetime datetime

SELECT @linked_server = 'FRICKE BMS';

exec dbo.LinkedServer_Status
    @linked_server, 
    @exists OUT, 
    @connected OUT, 
    @server_datetime OUT;

IF (@exists = 0)
    PRINT 'Linked Server "' + @linked_server + '" DOES NOT Exist';
ELSE BEGIN
    PRINT 'Linked Server "' + @linked_server + '" Exists';
    IF (@connected = 0)
        PRINT 'Linked Server "' + @linked_server + '" NOT Connected';
    ELSE
        PRINT 'Linked Server "' + @linked_server + '" IS Connected; Server DateTime: '+convert(varchar(25), @server_datetime, 120) 
END;

1
হাই, সেখানে সবার আগে স্বাগতম। কোনও অতিরিক্ত তথ্যবিহীন কোডের দেয়ালের চেয়ে জিনিসগুলি কীভাবে কাজ করে সে সম্পর্কে এখানে প্রায় কাছাকাছি আমরা কিছুটা ব্যাখ্যা চাই। তবে উত্তরের জন্য ধন্যবাদ।
টম ভি - টপ্যানসওয়ার্স.অক্সিজ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.