Innerhalb einer Triggerfunktion den kompletten Datensatz "wegschreiben"

Ich würde gerne innerhalb eines After-Insert/Update/Delete-Triggers den kompletten alten (OLD) und neuen (NEW) Datensatz, auf den sich das Ereignis auswirkt, in eine andere Tabelle rausschreiben. Bei Insert natürlich nur “NEW”, bei Delete nur “OLD”. Das ganze soll bei jeder existenten Tabelle passieren und die Datensätze sollen nach Möglichkeit alle in die gleiche Tabelle geschrieben werden, dass daraus sozusagen ein chonologisches Logfile aller Datenbank-Änderungen entsteht. Gibt es da Möglichkeiten, einen kompletten Datensatz ungeachtet seines Inhalts bspw. in eine Tabellenspalte vom Typ “bytea” zu kopieren und die Daten anschließend nach Möglichkeit auch wieder daraus zu lesen und wieder in die Ursprungstabelle zu schreiben?

Schau Dir mal tablelog von ads an, das macht (in etwas) das, was du willst. Allerdings brauchst für jede Tabelle eine spezielle history-table.


Andreas

Ich habe mal so etwas ähnliches geschrieben:

PgFoundry: Table Audit: Project Info
Log Table Changes in PostgreSQL with tablelog - ads’ corner

OK, das geht schonmal in die richtige Richtung. Wenn es wirklich auf mehrere Tabellen rausläuft, dann werde ich tablelog sicherlich mal ausprobieren. Meine eigentliche Frage war jedoch, ob man innerhalb einer Triggerfunktion die Möglichkeit hat, einen kompletten Datensatz bspw. als Bytestream in eine einzige gemeinsame Tabelle (Spalte vom Typ bytea) zu speichern. So muss ich lediglich diese eine Tabelle “von oben nach unten” durchgehen und sehe direkt, was auf der kompletten Datenbank im Laufe der Zeit so passiert ist.

Sicherlich machbar, aber diese Infos dann für ein Restore zu nutzen stelle ich mir eher knifflig vor …

Andreas

Es würde mir bereits weiterhelfen, wenn ich wüsste, wie man innerhalb einer Triggerfunktion mittels plpgsql einen record Spalte für Spalte durchlaufen und auf die Inhalte zugreifen könnte. Gibt es da eine Möglichkeit? Also ins Unreine gesprochen etwas wie folgt:

for spalten in NEW loop
bastelmirdarauseinbytea
end loop;
schreibebyteaingemeinsametabelle;

So könnte ich diese eine Triggerfunktion einer jeden neuen Tabelle zuweisen.

Das geht nicht mit plpgsql. Vielleicht könntest Du mit hstore was machen, aber generell gilt: du kannst nicht mit psql ohne wissen über die Spaltenstruktur auf Spalten zugreifen.

Andreas

OK, das ist mal ne Aussage.

hstore kommt für uns leider nicht in Frage, da wir noch Version 8.4 verwenden und ich gerade folgendes in der PgSQL-Onlinehilfe lesen musste:

In the current implementation, neither the key nor the value string can exceed 65535 bytes in length; an error will be thrown if this limit is exceeded. These maximum lengths may change in future releases.

65 kB ist doch etwas arg wenig.

Komme ich wohl um separate Tabellen doch nicht rum. Ich würde halt einen Lösungsansatz bevorzugen, der mit möglichst wenig Aufwand bei Kunden eingespielt werden kann. Ohne zusätzliche Module installieren oder den Postgres-Server erst nochmal manuell umkonfigurieren zu müssen. Ein simples SQL-Skript, das mir die entsprechende Logging-Funktion installiert (Triggerfunktionen und Trigger anlegt), wäre mir das liebste. Bei tablelog ist das ein wenig komplizierter, richtig?

Was willst du mit den Daten in einer Zelle anfangen? Wie willst du die wiederherstellen oder überhaupt auslesen?
Stelle ich mir schon arg kompliziert vor.

Aber wie gesagt, pl/pgSQL kann das nicht. Das war schon damals der Grund, warum ich C für table_log gewählt habe. Das hat sich bis heute nicht geändert.

Naja, ich dachte halt, es gäbe seitens plpgsql evtl. bereits Funktionen, die ganze Datensätze serialisieren und wieder deserialisieren könnten. Ähnlich wie in Java:

Serialisieren von Objekten

Damit hätte ich dann mein Vorhaben relativ einfach in die Tat umsetzen können und auch das Auslesen der Daten wäre damit kein Problem gewesen. Klar, aber wenn es das nicht gibt seitens plpgsql, dann wäre eine eigene Implementation schon recht aufwändig und v.a. fehleranfällig.

Zumindest ist mir keine derartige Funktion bekannt.
Da man in der Datenbank in der Regel auch per SQL auf die Logtabelle zugreifen will, macht das auch nur bedingt Sinn.