QA: Try/Catch i SQL 2005

Fråga: Vid användandet av Try/Catch i SQL Server 2005, kan jag då skräddarsy det felmeddelande som ska skickas tillbaka till klienten även om fel fångas i exempelvis en lagrad procedur?

Svar: Ja, när ett fel fångas så finns det fyra funktioner som returnerar information om det fel som uppstått, dessa är:

  • ERROR_NUMBER()
  • ERROR_MESSAGE()
  • ERROR_SEVERITY()
  • ERROR_STATE()

Detta innebär att i Catch-satsen så kan man antingen logga felet eller skapa sitt egna felmeddelande baserat på dessa funktioner. Exemplet nedan visar hur man t ex kan skapa ett felmeddelande som är det egentliga felmeddelandet inbakat som XML för vidare processande i ett annat lager än databasen.

Vi börjar med en enkel tabell:

 CREATE TABLE MyTable(id INT, name VARCHAR(10))

Om vi nu tänker oss en lagrad procedur där vi sätter in giltiga värden skulle det kunna se ut så här:

 INSERT INTO MyTable VALUES (1, 'String1')

Om vi nu tänker oss att jag försöker köra följande kod:

 INSERT INTO MyTable VALUES ('NotValid', 'String2')

Så skulle jag få följande felmeddelande:
Syntax error converting the varchar value 'NotValid' to a column of data type int.

För att lösa detta kan man bädda in uttrycket i en Try/Catch-sats enligt:

BEGIN TRY
   INSERT INTO MyTable VALUES ('NotValid', 'String2')
END TRY
BEGIN CATCH

   DECLARE @errMsg VARCHAR(500)
   SET @errMsg = '<ERROR>'
   SET @errMsg = @errMsg + '<CODE>' + CAST(ERROR_NUMBER() AS VARCHAR) + '</CODE>'
   SET @errMsg = @errMsg + '<MSG>' + CAST(ERROR_MESSAGE() AS VARCHAR(400)) + '</MSG>'
   SET @errMsg = @errMsg + '</ERROR>'
   RAISERROR(@errMsg, 17, 1)

END CATCH

Här har jag valt att skapa ett eget felmeddelande i XML-format med originalfelmeddelandets värden och får då följande:
<ERROR><CODE>245</CODE><MSG>Syntax error converting the varchar value 'NotValid' to a column of data type int.</MSG></ERROR>

Möjligheterna är stora; logga felmeddelandet, låt det bubbla vidare uppåt, skapa ett eget meddelande, exekvera annan kod osv.

Best practise är att alltid generera ett fel när ett sådant uppstår, inte att dölja dem i en Try/Catch-sats. Detta på grund av att felsökning blir snudd på omöjligt om man inte samtidigt loggar felet någon annanstans.