Eingabeprüfung mit Triggern


Es werden grundsätzlich keine Regeln (Rules) für die Prüfung von Nutzereingaben verwendet, sondern ausschließlich Trigger!

Die Prüfung von nutzerseitigen Eingaben in kvwmap erfolgt ausschließlich über Trigger und Triggerfunktionen. Der Trigger wird bei der entsprechenden Tabelle notiert und verweist auf die Triggerfunktion(en). Triggerfunktionen werden beim zugehörigen Schema gespeichert.

Der Weg ist: Zuerst die Triggerfunktionen und anschließend der Trigger.

Triggerfunktion

Die Triggerfunktion für die Prüfung der Nutzereingaben erhält den Namen der Tabelle, die geprüft wird, dahinter „_check_entries“. Beispiel:

kindertagespflege_person_check_entries

Die Funktion ist transaktional auszuführen, die ganze Anweisung steht also in

BEGIN
...
RETURN NEW;
END;

RETURN NEW wird immer vor dem letzten END notiert, das die Transaktion beendet und bedeutet, dass das INSERT bzw. das UPDATE auch tatsächlich ausgeführt wird. RETURN NEW muss notiert werden.

In der Transaktion kann die Anwendungsoperation unterschieden werden, bei Prüfungen also INSERT oder UPDATE. Dafür wird je ein IF notiert in der Form

IF (TG_OP = 'INSERT') THEN
  ...
END IF;
IF (TG_OP = 'UPDATE') THEN
  ...
END IF;

Wenn diese IFs weggelassen werden, wird die Prüfung bei beiden Anwendungsoperationen ausgeführt. Diese IFs können auch schon weitere Bedingungen enthalten, es ist aber übersichtlicher, die Prüfung in ein eigenes IF zu schreiben:

 IF (TG_OP = 'INSERT') THEN
  IF <prüfung> THEN
    ...
  END IF;
END IF;

Das Ergebnis der Prüfung mündet immer in einen Text, den der Nutzer bekommt. Dieser Text muss ihm alle notwendigen Informationen an die Hand geben, damit er weiß, was passiert ist.

Die Prüfung mündet in drei mögliche Zustände:

  • Die Prüfung mündet in einen Hinweis (INSERT bzw. UPDATE soll trotzdem durchgeführt werden)
 IF (TG_OP = 'INSERT') THEN
  IF <prüfung> THEN
    RAISE INFO 'Hier kommt der Hinweistext für den Nutzer';
  END IF;
END IF;



  • Die Prüfung mündet in eine Warnung (INSERT bzw. UPDATE soll trotzdem durchgeführt werden)
 IF (TG_OP = 'INSERT') THEN
  IF <prüfung> THEN
    RAISE WARNING 'Hier kommt die Warnung für den Nutzer';
  END IF;
END IF;



  • Die Prüfung ergibt einen Fehler (INSERT bzw. UPDATE soll NICHT durchgeführt werden)
 IF (TG_OP = 'INSERT') THEN
  IF <prüfung> THEN
    RAISE EXCEPTION 'Hier kommt die Fehlermeldung für den Nutzer';
  END IF;
END IF;



Statt RAISE INFO kann auch RAISE NOTICE verwendet werden.

 IF (TG_OP = 'INSERT') THEN
  IF <prüfung> THEN
    RAISE NOTICE 'Text, den der Nutzer lesen soll';
  END IF;
END IF;

Es kann statt des einfachen Textes ein JSON-String übergeben werden. kvwmap passt dann die Darstellung des Textes und des Hintergrundes an.

 IF (TG_OP = 'INSERT') THEN
  IF <prüfung> THEN
    RAISE NOTICE '{"success" : false, "msg_type" : "warning", "msg" : "Text, den der Nutzer lesen soll"}';
  END IF;
END IF;

„success“ entscheidet nur über die Hintergrundfarbe der Message und ist unwichtig für die Behandlung des Datensatzes. Ob die Verarbeitung des Datensatzes im Fehlerfall abgelehnt wird oder nicht, entscheidet ausschließlich ein gegebenenfalls danach notiertes RETURN NULL! RETURN NULL bedeutet, dass die ganze Transaktion sofort abgebrochen wird und lediglich die NOTICE ausgeliefert wird. Beachte: Bei RAISE EXCEPTION ist das nicht nötig.

Wenn bei RAISE NOTICE die Prüfung ergeben soll, dass der Datensatz nicht gespeichert wird, dann muss zusätzlich RETURN NULL notiert werden!

 IF (TG_OP = 'INSERT') THEN
  IF <prüfung> THEN
    RAISE NOTICE 'Text, den der Nutzer lesen soll';
    RETURN NULL;
  END IF;
END IF;



Bei RAISE-Texten können auch Werte aus new bzw. old eingefügt werden. An die Stelle im Text, wo der Wert stehen soll, wird ein Prozentzeichen gesetzt, nach dem Text wird mit Komma getrennt der Wert definiert:

THEN
  RAISE EXCEPTION 'Auftragsnummer % ist bereits vergeben!', upper(new.antragsnr);
END IF;



Trigger

Trigger zur Prüfung der Nutzereingaben sind grundsätzlich BEFORE-Trigger:

create trigger <name>
before insert or update
on <schema.tabelle>
for each row execute procedure <schema.triggerfuktion>();

Der Trigger könnte auch nur before insert oder nur before update sein, aber in der Regel sind beide Fälle nötig. Außerdem kann man den jeweiligen Anwendungsfall in der Triggerfunktion definieren, siehe oben.

Der Trigger sollte prinzipiell getrennt werden von sonstigen Triggern, die vielleicht auch noch an der Tabelle hängen und sonst was machen. Pro Tabelle sollte es im Regelfall höchstens genau einen Trigger zur Prüfung der Nutzereingaben geben.

Der Trigger zur Prüfung der Nutzereingaben soll grundsätzlich „check_entries“ heißen:

create trigger check_entries
before insert or update
on geodaten_landkreis.kindertagespflege_verantwortliche
for each row execute procedure geodaten_landkreis.kindertagespflege_person_check_entries();