W procedurach przechowywanych można i należy obsługiwać błędy za pomocą specjalnych konstrukcji.
W SQL Server główne mechanizmy to bloki TRY...CATCH, w których wszystkie błędy wewnątrz TRY są łapane, a w CATCH można zarejestrować szczegóły. Dostępne są funkcje takie jak ERROR_NUMBER(), ERROR_MESSAGE() do uzyskania szczegółów.
BEGIN TRY -- Ryzykowna operacja UPDATE Accounts SET balance = balance - 100 WHERE id = 1; END TRY BEGIN CATCH INSERT INTO ErrorLog( ErrorTime, ErrorNumber, ErrorMessage, UserName ) VALUES ( GETDATE(), ERROR_NUMBER(), ERROR_MESSAGE(), SUSER_SNAME() ); -- Dodatkowe przywracanie lub ROLLBACK END CATCH
W Oracle częściej używa się bloków EXCEPTION:
BEGIN UPDATE ...; EXCEPTION WHEN OTHERS THEN INSERT INTO error_log VALUES (..., SQLERRM); END;
Rzeczy, o których warto pamiętać:
Czy wyjątek w bloku CATCH może prowadzić do utraty kontekstu błędu? Jak zrealizować zagnieżdżoną obsługę błędów?
Odpowiedź i przykład: Jeśli w bloku CATCH wystąpi błąd (na przykład z powodu niedostępności tabeli ErrorLog), oryginalny kontekst błędu zostaje utracony, a informacja o przyczynie awarii może być zgubiona.
Aby się zabezpieczyć, encapsulate logowanie w osobnej procedurze z własnym TRY...CATCH, aby zawsze łapać "błąd w obsłudze błędów".
BEGIN TRY -- główny kod END TRY BEGIN CATCH EXEC LogError @Error = ERROR_MESSAGE(); END CATCH -- Procedura LogError sama zawiera swój TRY...CATCH
Historia
Projekt: Raportowanie finansowe. W procedurach przechowywanych dodano bloki TRY...CATCH, ale nie zalogowano parametrów, w których wystąpił błąd. W rezultacie przy łapaniu krytycznych awarii trzeba było ręcznie szukać sytuacji z kopii zapasowej – przyczyna pierwotna była nieoczywista.
Historia
Projekt: Automatyzacja obiegu dokumentów (Oracle). W bloku EXCEPTION zapomniano o zalogowaniu nazwy użytkownika. Po tygodniu dochodzenia odkryliśmy, że ktoś celowo "łamał" dokumenty — ustaliliśmy to tylko na podstawie pośrednich sygnałów w dzienniku audytu.
Historia
Projekt: E-commerce. Procedura przy awarii zapisywała błąd w ErrorLog. Pewnego dnia tabela Log została zablokowana przez rozrastającą się transakcję, a próba logowania doprowadziła do zagnieżdżonego błędu, który nadpisał oryginalną przyczynę i oczyścił stos błędów. Naprawiliśmy to wprowadzając dodatkową tabelę dla krytycznych awarii i wielopoziomowe logowanie.