Triggerfunktion BEFORE INSERT löst sich nie aus!

Probleme und Fragen zum Thema Trigger und Funktionen.
viglu
Neuer Benutzer
Beiträge: 3
Registriert: Fr 31. Jul 2009, 16:02

Triggerfunktion BEFORE INSERT löst sich nie aus!

Beitrag von viglu » Fr 31. Jul 2009, 22:06

Hallo,

Habe folgende Tabelle mit Triggerfunktion.

Code: Alles auswählen

CREATE DOMAIN "TIDNN"
  AS bigint
  NOT NULL;

CREATE TABLE "tblUser"
(
  "ID" "TIDNN" NOT NULL,
  "USERNAME" "TUSERNAMENN",
  "USERPASS" "TPASSWORD" NOT NULL,
  CONSTRAINT "PK_TBLUSER_ID" PRIMARY KEY ("ID")
);

CREATE TRIGGER test
  BEFORE INSERT
  ON "tblUser"
  FOR EACH ROW
  EXECUTE PROCEDURE "TF_TBLUSERTF_CHANGE"();


CREATE OR REPLACE FUNCTION "TF_TBLUSERTF_CHANGE"()
  RETURNS trigger AS
$BODY$
  BEGIN
    IF (NEW.ID IS NULL) THEN
   NEW.ID = nextval('seq_tbluser_id');
    END IF;
     
    RETURN NEW;
  END; $BODY$
  LANGUAGE 'plpgsql' VOLATILE
  COST 100;


Wenn ich jetzt ein INSERT-Statement ausführe wie

Code: Alles auswählen

insert into "tblUser" ("USERNAME", "USERPASS")
values('name', 'kennwort')

Bekomme ich eine Meldung "Die Domaine TIDNN autorisiert kein NULL Werte. Dabei setze ich doch gerade im BEFORE INSERT mit NEW.ID ein Wert hinein.

Warum funktioniert dies nicht ?

ads
Erfahrener Benutzer
Beiträge: 4148
Registriert: Mi 8. Feb 2006, 10:58
Wohnort: MD
Kontaktdaten:

Beitrag von ads » Sa 1. Aug 2009, 01:09

Also Sorry, du baust eine ganze Menge Unsinn hier ;-)

viglu hat geschrieben:

Code: Alles auswählen

CREATE DOMAIN "TIDNN"
  AS bigint
  NOT NULL;

Du definierst deine DOMAIN doch als NOT NULL, warum beschwerst du dich dann, wenn PostgreSQL das auch einhält? Lass das NOT NULL weg und das klappt.

Dann sind "TUSERNAMENN" und "TPASSWORD" nicht definiert, jedenfalls nicht in deinem Beispiel. Und ganz zum Schluß:

Code: Alles auswählen

IF (NEW.ID IS NULL) THEN
Du greifst hier effektiv auf die Spalte "id" zu, nicht auf "ID". Wenn du keine "" drumherum setzt, schreibt PostgreSQL die Bezeichner klein und das klein geschriebene "id" gibt es bei dir nicht.


So, und wohin darf ich jetzt eine Rechnung für Support am Wochenende schicken? ;-)
Xandrian: Kurz gesagt: Du hast ein falsches Konzept und willst nicht auf ads hören Bild

Jetzt NEU: PostgreSQL - Datenbankpraxis für Anwender, Administratoren und Entwickler

PostgreSQL Service & Support

viglu
Neuer Benutzer
Beiträge: 3
Registriert: Fr 31. Jul 2009, 16:02

Beitrag von viglu » Sa 1. Aug 2009, 09:23

Ich steige von Firebird auf Postgres über das mit den "" wusste ich nicht.

Du definierst deine DOMAIN doch als NOT NULL, warum beschwerst du dich dann, wenn PostgreSQL das auch einhält? Lass das NOT NULL weg und das klappt.

Aber ein Before-Trigger wird doch schon vor der Operation ausgelöst und somit auch bevor die Contraints auf TIDNN kontrolliert wird.

akretschmer
Erfahrener Benutzer
Beiträge: 7565
Registriert: So 29. Okt 2006, 13:35
Wohnort: Kaufbach, Sachsen, Germany, Germany
Kontaktdaten:

Beitrag von akretschmer » Sa 1. Aug 2009, 13:18

viglu hat geschrieben:Hallo,

Habe folgende Tabelle mit Triggerfunktion.

Code: Alles auswählen

CREATE DOMAIN "TIDNN"
  AS bigint
  NOT NULL;

CREATE TABLE "tblUser"
(
  "ID" "TIDNN" NOT NULL,
  "USERNAME" "TUSERNAMENN",
  "USERPASS" "TPASSWORD" NOT NULL,
  CONSTRAINT "PK_TBLUSER_ID" PRIMARY KEY ("ID")
);

CREATE TRIGGER test
  BEFORE INSERT
  ON "tblUser"
  FOR EACH ROW
  EXECUTE PROCEDURE "TF_TBLUSERTF_CHANGE"();


CREATE OR REPLACE FUNCTION "TF_TBLUSERTF_CHANGE"()
  RETURNS trigger AS
$BODY$
  BEGIN
    IF (NEW.ID IS NULL) THEN
   NEW.ID = nextval('seq_tbluser_id');
    END IF;
     
    RETURN NEW;
  END; $BODY$
  LANGUAGE 'plpgsql' VOLATILE
  COST 100;


Wenn ich jetzt ein INSERT-Statement ausführe wie

Code: Alles auswählen

insert into "tblUser" ("USERNAME", "USERPASS")
values('name', 'kennwort')

Bekomme ich eine Meldung "Die Domaine TIDNN autorisiert kein NULL Werte. Dabei setze ich doch gerade im BEFORE INSERT mit NEW.ID ein Wert hinein.

Warum funktioniert dies nicht ?



Neben dem, was ads sagte, frage ich mich, warum du nicht einfach die Spalte als SERIAL bzw. BIGSERIAL und als PRIMARY KEY deklarierst.
Dann erscheint mir das ganze Gehampel eh hyperfluid.

Andreas
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

ads
Erfahrener Benutzer
Beiträge: 4148
Registriert: Mi 8. Feb 2006, 10:58
Wohnort: MD
Kontaktdaten:

Beitrag von ads » Sa 1. Aug 2009, 13:19

Nicht wirklich.
Schreib mal in deine Funktion ein paar Debugmeldungen, das kannst du mittels:

Code: Alles auswählen

RAISE NOTICE 'ich bin gesprächig';

tun. Dann wirst du sehen, dass die Triggerfunktion höchstwahrscheinlich (hab es nicht probiert) nicht aufgerufen wird.

Du kannst das NOT NULL immer noch in deinem Trigger forcieren, aber wenn du die Domain schon als NOT NULL definierst, musst du Daten übergeben.
Xandrian: Kurz gesagt: Du hast ein falsches Konzept und willst nicht auf ads hören Bild

Jetzt NEU: PostgreSQL - Datenbankpraxis für Anwender, Administratoren und Entwickler

PostgreSQL Service & Support

viglu
Neuer Benutzer
Beiträge: 3
Registriert: Fr 31. Jul 2009, 16:02

Beitrag von viglu » Sa 1. Aug 2009, 15:13

Danke ads,

Postgres verhält sich gegen Firebird ein bisschen anders. Kann aber damit leben :)

ads
Erfahrener Benutzer
Beiträge: 4148
Registriert: Mi 8. Feb 2006, 10:58
Wohnort: MD
Kontaktdaten:

Beitrag von ads » Sa 1. Aug 2009, 19:55

Bitte schön ;-)
Xandrian: Kurz gesagt: Du hast ein falsches Konzept und willst nicht auf ads hören Bild

Jetzt NEU: PostgreSQL - Datenbankpraxis für Anwender, Administratoren und Entwickler

PostgreSQL Service & Support

symbiont
Erfahrener Benutzer
Beiträge: 1328
Registriert: Mo 17. Mär 2008, 11:45
Wohnort: NULL

Beitrag von symbiont » Mo 10. Aug 2009, 11:24

ads hat geschrieben:Du kannst das NOT NULL immer noch in deinem Trigger forcieren, aber wenn du die Domain schon als NOT NULL definierst, musst du Daten übergeben.


Das ist aber nicht ganz konsistent zu dem Verhalten von Postgres zu normalen NOT NULL attributen .. hmm

Diese kann man durchaus in einem BEFORE INSERT trigger initialisieren .. ohne sie vorher mit was nicht-nullem zu fuellen.

Obs nicht ein <jehova> ist?

ads
Erfahrener Benutzer
Beiträge: 4148
Registriert: Mi 8. Feb 2006, 10:58
Wohnort: MD
Kontaktdaten:

Beitrag von ads » Mo 10. Aug 2009, 13:41

symbiont hat geschrieben:Das ist aber nicht ganz konsistent zu dem Verhalten von Postgres zu normalen NOT NULL attributen .. hmm

Das Attribut ist ein Attribut der Domain.
Was du meinst, sind Constraints.

Beide werden unterschiedlich gehandhabt. Bei der Domain ist das Attribut quasi "fest dabei" und muss erfüllt werden. Der Constraint wird erst später überprüft.

Ich sehe da nicht wirklich eine Inkonsistenz, weil zwei verschiedene Features angesprochen werden. Gut, die haben beide den gleiche Namen, aber das war es auch schon.
Xandrian: Kurz gesagt: Du hast ein falsches Konzept und willst nicht auf ads hören Bild

Jetzt NEU: PostgreSQL - Datenbankpraxis für Anwender, Administratoren und Entwickler

PostgreSQL Service & Support

symbiont
Erfahrener Benutzer
Beiträge: 1328
Registriert: Mo 17. Mär 2008, 11:45
Wohnort: NULL

Beitrag von symbiont » Mo 10. Aug 2009, 14:30

ads hat geschrieben:Das Attribut ist ein Attribut der Domain.
Was du meinst, sind Constraints.


natuerlich constraints - auf ein attribut -> not null ..

Beide werden unterschiedlich gehandhabt.
schade ..

Bei der Domain ist das Attribut quasi "fest dabei" und muss erfüllt werden. Der Constraint wird erst später überprüft.


natuerlich muss auch das not-null constraint auf ein attribut letztendlich erfuellt sein. das ist ja das schoene an dem before-trigger, dass ich dort dafuer sorgen kann .. der wert eines attributes ist ja bekanntlich "ohne wert" solange er nicht in den speicher geschrieben wurde - was nach dem before trigger i.d.R. passiert.

aber was meinst du, dass ein attribut bei einer domain "dabei sei" .. so eine domain erfuellt doch eher die funktion eines types.

Ich sehe da nicht wirklich eine Inkonsistenz, ..


soeine domain ist ja letztendlich kaum mehr als ein satz herkoemmlicher "db-werkzeuge" um ein attribut zu definieren - also z.B. dessen wertebereich und regelwerke dazu - wie z.B. nullable oder nicht.

ich meine - mit der selben argumentation, mit der man das verhalten der domain vor/in/bei einem before-insert trigger begründen kann, koennte man auch für eine strikte erfuellung eines schnoeden not-null constraints vor dem before-trigger plädieren .. oder eben umgekehrt - wie der OP "erwarten" dass die regeln der domain nach dem before-trigger gecheckt werden

immerhin definiert man das not null in der domain ja auch als constraint - ich haette auch erwartet, dass dies zu dem gleichen zeitpunkt wie alle anderen constraints sichergestellt wird - das wäre konsequent / konsistent.

gläube mir - du würdest es auch hübscher finden :)

Antworten