RAISERROR generuje niestandardowy błąd w T-SQL, umożliwiając kontrolowane sygnalizowanie problemów aplikacji.
RAISERROR w języku T-SQL
RAISERROR to instrukcja języka Transact-SQL używana w Microsoft SQL Server do wygenerowania komunikatu lub błędu zdefiniowanego przez programistę. Może przekazać tekst bezpośrednio w instrukcji, odwołać się do komunikatu zapisanego w katalogu systemowym albo wykorzystać numer komunikatu i argumenty formatowane podobnie jak w funkcji printf. Przykładowa postać to RAISERROR (N'Nieprawidłowy identyfikator: %d', 16, 1, @Id). Pierwszy parametr określa treść, drugi poziom ważności, trzeci stan, a kolejne wartości uzupełniają znaczniki formatu.
W przypadku tekstu przekazywanego bezpośrednio instrukcja nie tworzy automatycznie trwałego wpisu w katalogu komunikatów. Dla komunikatów zarejestrowanych w SQL Server można użyć numeru identyfikacyjnego, między innymi po wcześniejszym dodaniu definicji przez sp_addmessage. Parametr tekstowy może mieć maksymalnie 2047 znaków, przy czym komunikat może zajmować więcej miejsca wewnętrznie, gdy zawiera symbole formatowania. Z tego powodu długi opis błędu warto przechowywać i przekazywać w sposób kontrolowany, zamiast budować go z przypadkowo łączonych fragmentów.
Poziom ważności, stan i sposób obsługi
Drugi argument RAISERROR przyjmuje poziom ważności od 0 do 25. Poziomy od 0 do 10 są traktowane jako komunikaty informacyjne, natomiast poziomy od 11 do 16 sygnalizują błędy możliwe do obsłużenia przez kod aplikacji lub procedurę T-SQL. Poziomy od 17 do 19 wskazują poważniejsze problemy związane z zasobami albo działaniem silnika. Poziomy od 20 do 25 oznaczają błędy krytyczne; ich użycie wymaga odpowiednich uprawnień i może spowodować zakończenie połączenia z SQL Server. Nie należy dobierać poziomu wyłącznie na podstawie brzmienia komunikatu, ponieważ wpływa on na zachowanie klienta i obsługę wyjątków.
Trzeci argument jest liczbą stanu od 0 do 255. Nie opisuje stopnia awarii, lecz pozwala rozróżnić miejsce lub wariant wystąpienia tego samego błędu. W procedurze zawierającej kilka ścieżek walidacji można więc użyć jednego komunikatu z różnymi wartościami stanu. Ułatwia to analizę logów i kodu wywołującego. Dla poziomów informacyjnych przydatna bywa opcja WITH NOWAIT, która wymusza natychmiastowe wysłanie komunikatu do klienta, zamiast oczekiwania na opróżnienie bufora komunikatów.
RAISERROR w procedurach i transakcjach
Instrukcja często występuje w procedurze składowanej, gdy warunek biznesowy lub techniczny uniemożliwia dalsze wykonywanie operacji. Przykładowo po sprawdzeniu danych wejściowych można wygenerować błąd poziomu 16, a następnie zakończyć procedurę instrukcją RETURN. Samo użycie RAISERROR nie zawsze kończy wykonywanie całego batcha, procedury ani transakcji. Kod musi świadomie określić dalszy przebieg, na przykład przez RETURN, obsługę TRY...CATCH albo wycofanie transakcji instrukcją ROLLBACK TRANSACTION.
W bloku CATCH można przekazać dalej informacje o przechwyconym błędzie, korzystając z funkcji takich jak ERROR_MESSAGE(), ERROR_NUMBER(), ERROR_LINE() i ERROR_PROCEDURE(). W starszym kodzie spotyka się ponowne zgłaszanie wyjątku przez RAISERROR, jednak trzeba pamiętać o skutkach dotyczących numeru, poziomu ważności i stanu błędu. Opcja WITH SETERROR ustawia wartości zwracane przez @@ERROR także wtedy, gdy komunikat ma poziom ważności 10 lub niższy. Z kolei WITH LOG zapisuje komunikat w dzienniku błędów SQL Server i dzienniku aplikacji systemu Windows, ale wymaga odpowiednich uprawnień albo poziomu ważności umożliwiającego taki zapis.
Różnica między RAISERROR a THROW
W nowszym kodzie T-SQL warto rozważyć instrukcję THROW, szczególnie gdy celem jest ponowne zgłoszenie błędu przechwyconego w bloku CATCH. Bez parametrów, jako THROW;, zachowuje pierwotne informacje o wyjątku, w tym jego numer, poziom ważności, stan i miejsce wystąpienia. RAISERROR pozostaje użyteczny między innymi do komunikatów informacyjnych, natychmiastowego raportowania postępu przez WITH NOWAIT, korzystania z formatowania argumentów oraz obsługi starszych procedur.
Najczęstsze problemy wynikają z pomieszania komunikatu informacyjnego z błędem przerywającym operację, nieuwzględnienia wpływu instrukcji na transakcję albo użycia nieprawidłowej liczby argumentów formatu. Podczas diagnozy trzeba sprawdzić pełną instrukcję, poziom ważności, stan, kontekst TRY...CATCH, wartość @@TRANCOUNT oraz zachowanie klienta łączącego się z SQL Server. Sam tekst komunikatu nie wystarcza do ustalenia, czy transakcja została wycofana, połączenie zamknięte lub procedura kontynuowała działanie.