wie erstelle ich bedingte trigger?

Hallo,

Bezüglich des “Features” : table_log-0.4.4.tar.gz
hätte ich eine Frage:

Nachdem ich das obige Programm (von ADS glaube ich) bei mir erfolgreich eingebaut habe, kommt nun die Einschränkung, dass nur unter gewissen Umständen eine Zeile protokolliert werden soll…
Wird dies über den Trigger gelöst?

Wenn ich das soweit verstanden habe, bewirkt ein Trigger, dass auf eine gewisses Ereigniss hin, etwas getan wird…

table_log beispielsweise erzeugt folgende trigger:

CREATE TRIGGER "table_log_trigger" AFTER INSERT OR UPDATE OR DELETE 
ON "public"."t_kvpos" FOR EACH ROW 
EXECUTE PROCEDURE "public"."table_log"(t_kvpos_log, 1, public);

Dies hört sich nach folgendem an:
Immer wenn auf t_kvpos ein update/insert oder delete gemacht wird, wird eine externe Funktion table_log aufgerufen???

Die Funktion table_log gibts auch bei mir in der Datenbank…

CREATE OR REPLACE FUNCTION "public"."table_log" () RETURNS trigger AS
'$libdir/table_log', 'table_log'
LANGUAGE 'c' VOLATILE CALLED ON NULL INPUT SECURITY INVOKER;

Das obige bedeutet wohl, es wird eine Funktion/Programm auf meinem Server aufgerufen und diese gibt wieder einen Trigger zurück???

Naja… Mein Ziel soll sein, dass dieses tablelogging nur dann durchgeführt werden soll, wenn sich in gewissen Spalten der Wert ändert…
Wo ist dies zu tun?

Im trigger oder in der Funktion?
Ich denke mal im trigger aber wo schreibe ich dann die Einschränkung hin?

Irgendwo muss doch was hin in der Form

If (old.nekp != new.nekp) OR
   (old.nvkp != new.nVKP) OR...
       EXECUTE PROCEDURE "public"."table_log"(t_kvpos_log, 1, public);
Else
   ...

Könnte es aber auch sein, dass ich eine neue Funktion erschaffen muss, die von dem trigger immer aufgerufen wird, ich aber in der Funktion dann die obige Entscheidung treffe???

Ganz sicher wird sich ads dazu noch melden, ja, das stammt von ihm.

Von mir nur so viel:

Du kannst in der Triggerfunction (hier in C geschrieben) solche Tests durchführen. Entweder modifizierst Du den Code dahingehend, oder aber Du schreibst einen Wrapper in z.B. pl/pgsql, der den Test durchführt und dann erst ads seine Funktion aufruft. Das wäre das, was mir spontan einfällt, mehr von ads, sobald er wach ist…

Andreas

Die aufgerufene Funktion ist in C geschrieben, wenn du Änderungen daran vornehmen möchtest, wirst du den C-Code umschreiben müssen.

Das mit dem Wrapper wird vielleicht nicht so einfach funktionieren, da die C-Funktion direkten Zugriff auf die alten und neuen Werte haben möchte. Ich weiss nicht, ob das auch noch klappt, wenn die Funktion nicht direkt vom Trigger sondern von einer anderen Funktion aufgerufen wird.

Was genau möchtest du denn nicht loggen?

folgendes habe ich gemacht:

CREATE OR REPLACE FUNCTION table_log_kvpos() RETURNS TRIGGER AS $table_log_kvpos$
BEGIN
	-- Bei Delete muss immer der alte Record zurückgegeben werden
	IF (TG_OP = 'DELETE') THEN
    	table_log(t_kvpos_log, 1, public);
        RETURN old
    END IF; 
    -- Bei Insert oder Update muss imer der neue Record zurückgegeben werden 
    IF (old.nvkp != new.nvkp) THEN
    	table_log(t_kvpos_log, 1, public);
 	END IF;
    RETURN new;
END;
$table_log_kvpos$ LANGUAGE 'plpgsql' VOLATILE CALLED ON NULL INPUT SECURITY INVOKER;

leider bekomme ich einen Fehler der Form:
FEHLER: Fehler »Syntaxfehler« bei »table_log« at character 1
QUERY: table_log(t_kvpos_log, 1, public)
CONTEXT: SQL statement in PL/PgSQL function “table_log_kvpos” near line 4

er kommt mit dem Aufruf der Funktion table_log() nicht wirklich klar…
ich habe auch schon “Call table_log()” probiert…
wie rufe ich in einer Funktion eine andere Funktion auf?
Die Beispiele in der Doku, die ich gefunden habe, machen halt direkt ihren Code, ohne eine andere Funktion aufzurufen…


PS:
ich mache also folgendes:

  • ich versuche die obige Funktion zum laufen zu bringen
  • der Trigger für die t_kvpos wird so geändert:
CREATE TRIGGER "table_log_trigger" AFTER INSERT OR UPDATE OR DELETE 
ON "public"."t_kvpos" FOR EACH ROW 
EXECUTE PROCEDURE "public"."table_log_kvpos"();

Die table_log() Funktion ist als Trigger Funktion definiert und erwartet direkt keine Argumente. Du kannst sie in der gegebenen Formnur direkt durch einen Trigger aufrufen lassen - wie gesagt, als Wrapper wird das nichts. Dazu müsste man die Funktion umschreiben.

Wenn du aber sowieso schon in den C-Code musst, wäre die Änderung, die du da abfragst, auch relativ einfach umzusetzen.

select function() bzw., select * from function() …

Andreas

OK. Erst mal vielen Dank!

Ich werde wohl statt deine Funktionalität mir anzupassen, eher eine kleinere schreiben…

Im Detail geht es darum, wenn in einer Kaufvertragstabelle sich die Einkaufs- oder Verkaufspreise ändern, dies in einer Historientabelle festzuhalten…

Wenn dann eine Statistik vom Januar gefragt ist, werden halt die Januarwerte aus der Historie verwendet, bei Februar dann die ältesten DS maximal bis Februar…

ich denke dass dein tablelogging für meine Bedürfnisse sowas darstellt, wie Kanonen für Spatzen…

trotzdem Danke…

CREATE OR REPLACE FUNCTION table_log_kvpos() RETURNS TRIGGER AS $table_log_kvpos$
BEGIN
– Bei Insert oder Update muss imer der neue Record zurückgegeben werden
IF (old.nvkp != new.nvkp) THEN
INSERT INTO t_kvposlog current_timestamp, old.nvkp, … ;
END IF;

RETURN new;
END;
$table_log_kvpos$ LANGUAGE ‘plpgsql’ VOLATILE CALLED ON NULL INPUT SECURITY INVOKER;

Sieht gut aus.

tablelog ist nur darum in C geschrieben, weil man in plpgsql nicht direkt herausfinden kann, welche Spalten es in OLD und NEW gibt.

Das geht mittlerweile auch über Umwege, aber damals[tm] in 2001 war das so gut wie gar nicht möglich.


Wenn man die Spaltennamen weiss (sprich, nur für eine sezifische Tabelle ein Logging benötigt), dann ist die Sache einfach.