Wyzwalacz z instrukcją RAISERROR generuje niestandardowy komunikat błędu w reakcji na niedozwoloną operację.
Rola wyzwalacza w SQL Server
Wyzwalacz, czyli trigger, jest obiektem bazy danych Microsoft SQL Server uruchamianym automatycznie w następstwie określonego zdarzenia. Wyzwalacz DML może reagować na instrukcje INSERT, UPDATE albo DELETE wykonywane na tabeli lub widoku. Jego kod działa w kontekście tej samej transakcji co instrukcja, która go uruchomiła. Dzięki temu może sprawdzić dane dopiero po ich przekazaniu do operacji i zablokować zapis, jeśli narusza on regułę biznesową albo techniczną.
Wyzwalacz z instrukcją RAISERROR służy do przekazania aplikacji lub użytkownikowi własnego komunikatu o przyczynie odrzucenia operacji. Przykładowo trigger może wykryć próbę ustawienia ujemnej liczby sztuk, zmianę identyfikatora właściciela rekordu albo zapis daty niespełniającej warunku określonego w procedurze. Sam komunikat nie zastępuje jednak logiki transakcyjnej: aby anulować zmianę, kod wyzwalacza zwykle musi wykonać ROLLBACK TRANSACTION albo doprowadzić do przerwania instrukcji przez obsługę błędu.
Składnia RAISERROR i parametry komunikatu
W SQL Server instrukcja ma postać RAISERROR (message, severity, state), gdzie message może być tekstem, numerem komunikatu zdefiniowanego w katalogu systemowym albo zmienną zawierającą treść. Parametr severity określa poziom ważności błędu, a state jest jednobajtową wartością pomocniczą pozwalającą wskazać miejsce lub wariant wystąpienia problemu. Dla komunikatu tworzonego bezpośrednio w kodzie najczęściej stosuje się poziom ważności od 11 do 16, ponieważ są to błędy użytkownika, które mogą zostać obsłużone przez aplikację.
Przykładowy fragment triggera może wyglądać następująco: RAISERROR (N'Operacja narusza regułę danych.', 16, 1); ROLLBACK TRANSACTION;. Litera N oznacza stałą Unicode, co pozwala zachować polskie znaki. Instrukcja obsługuje również parametry formatowane, między innymi przez symbole takie jak %d dla liczby całkowitej lub %s dla tekstu. Opcja WITH NOWAIT wymusza natychmiastowe wysłanie komunikatu do klienta, natomiast WITH LOG zapisuje komunikat w dzienniku aplikacji Windows, jeśli spełnione są wymagania dotyczące poziomu ważności i uprawnień.
Przerwanie operacji i zachowanie transakcji
Ważną cechą RAISERROR jest to, że samo zgłoszenie błędu nie zawsze kończy wykonywanie kodu i nie wykonuje automatycznie wycofania całej transakcji. W triggerze trzeba więc świadomie zaprojektować dalsze zachowanie. Typowy schemat sprawdza tabelę logiczną inserted, zawierającą nowe wersje wierszy, oraz ewentualnie tabelę deleted, zawierającą wersje poprzednie. Jeśli warunek jest spełniony, wyzwalacz zgłasza błąd i wykonuje ROLLBACK TRANSACTION. W efekcie anulowana zostaje instrukcja, która uruchomiła trigger, a przy odpowiedniej konstrukcji także zmiany wykonane wcześniej w tej samej transakcji.
Wyzwalacz musi obsługiwać operacje wielowierszowe. Instrukcja UPDATE albo INSERT może zmienić wiele rekordów podczas jednego wywołania, dlatego sprawdzanie pojedynczej wartości lokalnej lub użycie konstrukcji zakładającej jeden wiersz prowadzi do niepełnej walidacji. Warunek powinien być zapisany jako zapytanie operujące na całym zbiorze inserted. Trzeba także uważać na zagnieżdżone wyzwalacze i ponowne uruchamianie triggerów, ponieważ modyfikacja innej tabeli w jego kodzie może uruchomić kolejne mechanizmy. Błąd zgłoszony z poziomem 11–19 może być przechwycony przez TRY...CATCH; w bloku CATCH można użyć między innymi funkcji ERROR_MESSAGE(), ERROR_NUMBER() i ERROR_STATE().
Kontrola błędów w działającej bazie SQL Server
Podczas diagnostyki należy ustalić, jaki typ wyzwalacza jest zdefiniowany, na której tabeli działa i dla jakich zdarzeń został utworzony. Pomocne są widoki katalogowe, takie jak sys.triggers, sys.trigger_events oraz sys.sql_modules, które pozwalają odczytać metadane i treść kodu. Należy sprawdzić, czy warunek odnosi się do wszystkich wierszy z tabeli inserted, czy komunikat jest jednoznaczny oraz czy po RAISERROR następuje poprawne zakończenie transakcji. Warto również przeanalizować procedurę lub aplikację wywołującą zapis, ponieważ może ona ignorować błąd, wykonywać własny rollback albo prezentować użytkownikowi wyłącznie ogólny komunikat.
W nowszych wersjach SQL Server do nowych implementacji często rozważa się THROW, ponieważ zachowuje bieżący błąd i lepiej współpracuje z obsługą wyjątków. Istniejący trigger z RAISERROR należy jednak oceniać zgodnie z jego konkretną składnią, poziomem ważności i sposobem obsługi transakcji. Niebezpieczne jest używanie wysokich poziomów ważności bez uzasadnienia: poziom 20 lub wyższy oznacza błąd krytyczny i może zakończyć połączenie klienta, a poziomy 19–25 podlegają dodatkowym ograniczeniom uprawnień. Test powinien obejmować pojedynczy rekord, wiele rekordów, próbę zapisu poprawnego i niepoprawnego oraz zachowanie aplikacji po odrzuceniu transakcji.