Home Full Site
SQL Stored Procedure에서의 에러 처리

SQL Server의 Stored Procedure (저장 프로시져, SP)에서 에러 처리를 하기 위해서 흔히 TSQL의 RAISERROR를 사용한다. (SQL 2012에는 THROW를 사용할 수도 있다) RASIERROR는 파라미터로 Message, Severity, State 등을 갖는데, 여기서 Severity는 중요한 의미를 갖는다. 만약 Severity가 0부터 10사이인 경우 이는 Information 혹은 Warning에 해당되서 TSQL의 TRY...CATCH 블력이 있더라도 CATCH 블럭으로 이동하지 않고 다음 TSQL 문장으로 진행한다. 하지만 먄약 Severity가 11이상인 경우 이는 에러에 해당되어 CATCH 블럭으로 이동하게 된다. 아래는 Informational Severity 와 Error Severity를 함께 사용한 Stored Procedure 예제이다.

예제

CREATE PROC sp_GetData
(
  @type int,
  @output varchar(50) OUTPUT
)
AS
BEGIN TRY
   DECLARE @data varchar(100)
  
   IF @type < 0 OR @type > 10
      -- 프로그래밍 에러 : Severity 11-16
      RAISERROR('Error: invalid input in @type', 16, 1)
  
   SELECT TOP 1 @data = data
   FROM Table1
   WHERE [TYPE] = @type
   ORDER BY Id
  
   IF LEN(@data) > 50
   BEGIN
      SET @output = SUBSTRING(@data, 0, 50)
      -- Info 혹은 Warning : Severity 0-10
      RAISERROR('Info: truncate data (max=50)', 2, 1)
   END      
   ELSE
      SET @output = @data

   RETURN 1
END TRY
BEGIN CATCH
    DECLARE @ErrorMessage NVARCHAR(4000);
    DECLARE @ErrorSeverity INT;
    DECLARE @ErrorState INT;
    SELECT @ErrorMessage = ERROR_MESSAGE(),
           @ErrorSeverity = ERROR_SEVERITY(),
           @ErrorState = ERROR_STATE();
    RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState);
END CATCH
RETURN 0
GO  



C#에서 Stored Procedure 에러 처리

C# / ADO.NET 프로그램 입장에서 보면, Informational Severity 레벨의 정보 혹은 경고들은 Exception (SqlException)으로 처리되지 않고 C#의 catch 블럭에서 잡을 수 없다. 이 정보/경고를 받기 위해서는 SqlConnection 객체의 InfoMessage 이벤트를 핸들링해줘야 한다. 반면 Stored Procedure에서 발생한 Severity 11이상의 에러들은 C#의 catch 블력으로 잡히게 되고, 일반적으로 SqlException으로 잡을 수 있다. SP를 어떻게 작성하는가에 따라 다르겠지만, 일반적으로 Informational인 경우 SP결과를 정상적으로 처리하고, Error인 경우 SP 결과를 무효화한다.

예제

static void Main(string[] args)
{
    CallSP(2);   // Normal
    CallSP(4);   // Info
    CallSP(200); // Error
}

static void CallSP(int type)
{
    string strCn = "Data Source=.;Initial Catalog=MyDB;Integrated Security=true";

    try
    {
        using (SqlConnection conn = new SqlConnection(strCn))
        {
            conn.Open();

            // Informational 이벤트를 핸들링 (Severity:0-10)
            conn.InfoMessage += new SqlInfoMessageEventHandler(conn_InfoMessage);

            SqlCommand cmd = new SqlCommand("sp_GetData", conn);
            cmd.CommandType = CommandType.StoredProcedure;

            // Input param
            SqlParameter pInput = new SqlParameter("@type", SqlDbType.Int);
            pInput.Direction = ParameterDirection.Input;
            pInput.Value = type;
            cmd.Parameters.Add(pInput);

            // Output param
            SqlParameter pOutput = new SqlParameter("@output", SqlDbType.VarChar, 50);
            pOutput.Direction = ParameterDirection.Output;
            cmd.Parameters.Add(pOutput);
                    
            // Run SP
            cmd.ExecuteNonQuery();

            Console.WriteLine(pOutput.Value); // output
            Console.WriteLine();
        }
    }
    catch (SqlException e)  // 에러 : Severity=11+ 인 경우
    {
        Console.WriteLine("(Error) No Output for SP call - {0}", e.Message);                
    }
    catch (Exception ex)
    {
        throw ex;
    }
}

static void conn_InfoMessage(object sender, SqlInfoMessageEventArgs e)
{
    Console.WriteLine("(Informational Message) {0}", e.Message);            
}



실행 샘플


© csharpstudy.com