Wir sind jetzt wie geheime Agenten – unsere Funktionen und Prozeduren führen Missionen aus: sie verarbeiten Daten, machen Berechnungen oder zaubern einfach ein bisschen Magie in der Datenbank. Aber wie merkt man, wenn etwas schief läuft? Wie findet man heraus, an welcher Stelle das "Massagebad für Daten" kaputt gegangen ist? Hier kommen Logging und Fehlerbehandlung ins Spiel.
Erinnerst du dich, wir haben schon angefangen zu schauen, wie man in PostgreSQL und PL/pgSQL "kommuniziert" und Logs schreibt:
RAISE NOTICE: entspannter, freundlicher Ton – "Hey, alles okay hier, aber vielleicht willst du mal draufschauen".RAISE WARNING: etwas lauter – "Uff, hier ist was komisch, vielleicht solltest du mal reinschauen".RAISE EXCEPTION: Panik-Sirene – "STOP! Der Algorithmus ist in Gefahr! Wir haben die Ausführung gestoppt, damit nicht alles den Bach runtergeht".
Jedes dieser Level hat seinen eigenen Zweck, und es ist wichtig, das richtige auszuwählen.
So sehen diese Nachrichten im Code aus:
DO $$
BEGIN
-- Level NOTICE (alles okay, nur eine Info)
RAISE NOTICE 'Nur eine Info: Datenverarbeitung gestartet';
-- Level WARNING (etwas Verdächtiges)
RAISE WARNING 'Warnung: Datenformat in der Spalte könnte falsch sein';
-- Level EXCEPTION (kritischer Fehler)
RAISE EXCEPTION 'Fehler: Eingabewert ist ungültig!';
END $$;
Wann verwenden:
RAISE NOTICE– für Debugging und entspannte Infos.RAISE WARNING– um auf potenziell falsche Daten hinzuweisen.RAISE EXCEPTION– wenn kritische Fehler auftreten, bei denen die Funktion gestoppt werden muss.
Fehlerbehandlung mit RAISE EXCEPTION
RAISE EXCEPTION ist dein Not-Aus. Wenn etwas schief läuft, kannst du die Ausführung der Funktion stoppen und eine Fehlermeldung ausgeben.
Noch mal zur Erinnerung, die Basis-Nutzung sieht so aus:
RAISE EXCEPTION 'Deine Fehlermeldung';
Aber um die Nachrichten informativer zu machen, kannst du Variablen verwenden:
DECLARE
input_value INTEGER;
BEGIN
input_value := NULL;
IF input_value IS NULL THEN
RAISE EXCEPTION 'Fehler: Eingabewert ist NULL. Erwartet wurde ein INTEGER';
END IF;
END;
Nachrichten formatieren
Du kannst Variablen direkt in den Nachrichtentext einbauen:
DECLARE
var1 TEXT := 'Daten';
var2 INTEGER := 42;
BEGIN
RAISE EXCEPTION 'Fehler bei der Verarbeitung von % mit ID %', var1, var2;
END;
Ausgabe: Fehler bei der Verarbeitung von Daten mit ID 42.
Beispiel: Datenvalidierung
Stell dir vor, du hast eine Prozedur, die das Alter einer Person entgegennimmt. Wenn das Alter negativ ist, macht es Sinn, einen Fehler zu werfen:
CREATE OR REPLACE FUNCTION validate_age(age INTEGER)
RETURNS VOID AS $$
BEGIN
IF age < 0 THEN
RAISE EXCEPTION 'Alter darf nicht negativ sein: %', age;
END IF;
END;
$$ LANGUAGE plpgsql;
-- Funktionsaufruf
SELECT validate_age(-5); -- Wirft einen Fehler
Informieren mit RAISE NOTICE
Wenn RAISE EXCEPTION die Sirene ist, dann ist RAISE NOTICE ein freundschaftliches Schulterklopfen. Mit diesem Level kannst du Kommentare einbauen, damit man versteht, was in der Funktion passiert.
Wann RAISE NOTICE verwenden:
- Debug-Infos ausgeben (z.B. aktueller Stand von Variablen).
- Nachricht über den Start eines Schritts oder das Ergebnis einer Berechnung.
Beispiel: Info-Nachrichten
CREATE OR REPLACE FUNCTION calculate_discount(price NUMERIC, discount_rate NUMERIC)
RETURNS NUMERIC AS $$
DECLARE
final_price NUMERIC;
BEGIN
RAISE NOTICE 'Preis vor Rabatt: %', price;
RAISE NOTICE 'Rabatt-Satz: %', discount_rate;
final_price := price - (price * discount_rate);
RAISE NOTICE 'Endpreis: %', final_price;
RETURN final_price;
END;
$$ LANGUAGE plpgsql;
-- Funktionsaufruf
SELECT calculate_discount(100, 0.2);
-- Gibt aus:
-- NOTICE: Preis vor Rabatt: 100
-- NOTICE: Rabatt-Satz: 0.2
-- NOTICE: Endpreis: 80
Praxis: Planung und Logging
Angenommen, du hast eine komplexe Datenverarbeitungsprozedur und willst wissen, an welchem Schritt sie gerade ist:
CREATE OR REPLACE FUNCTION process_data_step_by_step()
RETURNS VOID AS $$
BEGIN
RAISE NOTICE 'Schritt 1: Datenvorbereitung';
-- Deine Logik für den ersten Schritt
RAISE NOTICE 'Schritt 2: Datenvalidierung';
-- Deine Logik für den zweiten Schritt
RAISE NOTICE 'Schritt 3: Daten speichern';
-- Deine Logik für den dritten Schritt
END;
$$ LANGUAGE plpgsql;
-- Funktionsaufruf
SELECT process_data_step_by_step();
-- Im Log sieht man die Schritte nacheinander
Noch ein Beispiel. Stell dir einen Shop vor, der Rabatte nur für Bestellungen über einem bestimmten Betrag anbietet:
CREATE OR REPLACE FUNCTION apply_discount(order_amount NUMERIC)
RETURNS NUMERIC AS $$
BEGIN
IF order_amount < 50 THEN
RAISE EXCEPTION 'Fehler: Bestellwert muss mindestens 50 sein, aktueller Wert: %', order_amount;
END IF;
RETURN order_amount * 0.9; -- 10% Rabatt anwenden
END;
$$ LANGUAGE plpgsql;
-- Funktionsaufruf
SELECT apply_discount(30); -- Fehler: Bestellwert muss mindestens 50 sein
Typische Fehler
Fehler 1: Logging von Nachrichten ohne Parameter.
Sieht nicht sehr hilfreich aus, vor allem in großen Prozeduren:
RAISE NOTICE 'Fehler ist aufgetreten'; -- Warum? Wo? Wie?
Empfehlung: Immer Kontext hinzufügen:
RAISE NOTICE 'Fehler in Funktion process_data(): Eingabewert: %', input_value;
Fehler 2: RAISE EXCEPTION verwenden, wo RAISE WARNING reichen würde.
Wenn du zu viele Exceptions wirfst, wird der Code bei jedem kleinen Problem abgebrochen, was die Datenverarbeitung erschwert.
Tipp: Logging-Level bewusst einsetzen. Für Debugging NOTICE, für kritische Fälle EXCEPTION.
Fehler 3: Logging komplett weglassen.
Das ist wie Schlüssel im dunklen Zimmer suchen. Ohne Logs wird das Debuggen von komplexen Prozessen fast unmöglich.
Tipp: Füge RAISE NOTICE an den wichtigsten Stellen in der Funktion ein, besonders wenn sie groß und komplex ist.
GO TO FULL VERSION