Function/Trigger mit Java erstellen

Hallo,

eigentlich gehört dieses Problem wohl eher unter die Rubrik “Programmierung”, aber irgendwie kann ich dort nicht die Übersicht öffnen und was reinschreiben. Deshalb versuche ich es mal hier, da es ja auch was mit Funktionen und Triggern zu tun hat.

Und zwar möchte ich in einer Java-Anwendung (Swing) eine Tabelle einer PostgreSQL-DB neu anlegen. Dazu erstelle ich den SQL-Code und schicke den dann zur DB. Zum Teil klappt das auch (“DROP TABLE IF EXISTS tabelle” und “CREATE TABLE tabelle(…)”), aber wenn ich eine Funktion anlegen möchte (“CREATE OR REPLACE FUNCTION…”), bekomme ich eine PSQLException: “FEHLER: syntax error am Ende der Eingabe”.

Bisher hatte ich die SQL-Anweisungen für die Tabellen, Funktionen und Trigger in einer SQL-Datei stehen, die ich in psql mit

 \i /home/.../database/dbstruktur.sql

dann auch erfolgreich ausgeführt habe.

Der Code für die Funktion und den Trigger sieht so aus:

CREATE OR REPLACE FUNCTION date_lastchange()
RETURNS trigger
AS $$
BEGIN
IF TG_OP = ‘INSERT’ THEN
NEW.datum_angelegt := NOW();
ELSE
– ursprünglichen Wert behalten beim Update
NEW.datum_angelegt := OLD.datum_angelegt;
END IF;

– Zeit der letzten Änderung setzen
NEW.datum_geaendert := NOW();

RETURN NEW;
END;
$$
LANGUAGE ‘plpgsql’;


CREATE TRIGGER date_lastchange BEFORE INSERT OR UPDATE ON stamm
FOR EACH ROW EXECUTE PROCEDURE date_lastchange();

Ich vermute mal, das Problem ist die Schreibweise der Funktion. Ich hab die nämlich in Java in einen String reingeschrieben, den ich dann mit execute(sql) zur Datenbank geschickt habe. Vielleicht sind ja in der Funktion die Zeilenumbrüche wichtig.

Vielleicht kann mir jemand helfen und sagen, was ich da falsch gemacht habe oder wie es besser und richtig geht.

Gruss
heyho

Beim Ausführen von SQL Befehlen über JDBC gibt es zwei Regeln:

  • Am Ende(!) darf kein Semikolon stehen (bei CREATE FUNCTION innerhalb der Funktion natürlich schon)
  • Du kannst immer nur ein Statement ausführen (also CREATE FUNCTION und CREATE TRIGGER im gleichen String geht nicht)

OK, dann lag das Problem wohl am Semikolon am Ende von CREATE FUNCTION. Wobei ich bei den SQL-Anweisungen DROP TABLE IF EXISTS… und CREATE TABLE… jeweils am Ende auch ein Semikolon habe und dies problemlos durchging bzw. ich keine Fehlermeldung bekommen habe.

Ich hatte die beiden Anweisungen CREATE FUNCTION und CREATE TRIGGER in zwei verschiedenen Strings, und nur hier zusammen reinkopiert.

Ich versuch das jetzt mal ohne Semikolon und meld mich gleich wieder…

Hab jetzt mal alle Semikolons am Ende der SQL-Anweisungen rausgenommen. Bekomme aber immer noch diese Fehlermeldung. Danach (hinter “SQL:”) hab ich mal den String mit dem SQL-Code ausgegeben.

org.postgresql.util.PSQLException: FEHLER: syntax error am Ende der Eingabe
  Position: 310

SQL: CREATE OR REPLACE FUNCTION date_lastchange() RETURNS trigger AS $$ BEGIN IF TG_OP = 'INSERT' THEN NEW.datum_angelegt := NOW(); ELSE -- ursprünglichen Wert behalten beim Update NEW.datum_angelegt := OLD.datum_angelegt; END IF; -- Zeit der letzten Änderung setzen NEW.datum_geaendert := NOW(); RETURN NEW; END; $$ LANGUAGE 'plpgsql'

Hast Du den String wirklich ohne Zeilenumbruch gemacht?
Nachdem Du einen Zeilenkommentar (-- ursprünglichen …) verwendest, muss am Ende des Kommentars ein Zeilenumbruch ‘\n’ kommen.
Sonst geht der Kommentar im Prinzip bis zum Ende des Strings (und dann stimmt natürlich die Syntax nicht mehr)

Nur sicherheitshalber noch gefragt:
Welche Treiberversion verwendest Du eigentlich?
Das Dollarquoting funktioniert nämlich erst ab der Version 8.1 (oder war’s 8.2?)

Ja, der String ist ohne Zeilenumbrüche, an einem Stück. So wie er oben ausgegeben wurde. Ich kann ja mal die Kommentare rausnehmen. Die brauch ich in diesem Fall ja nicht. Wahrscheinlich lags daran. Klingt ja auch logisch…

Nur sicherheitshalber noch gefragt:
Welche Treiberversion verwendest Du eigentlich?
Das Dollarquoting funktioniert nämlich erst ab der Version 8.1 (oder war’s 8.2?)

Die DB ist Version 8.3. Mit Treiber meinst du wohl den JDBC-Treiber: der ist postgresql-8.4-701.jdbc4.jar. Hatte halt bei der DB ein paar mal zwischen 8.3 und 8.4 gewechselt. Dürfte aber hoffentlich nicht schlimm sein, oder soll ich da auch den Treier für 8.3 verwenden?

Was aber auch noch seltsam ist: es gibt zwar die Fehlermeldung, aber irgendwie scheint es trotzdem zu funktionieren.

Also, meine SQL-Anweisungen sind:
1.) DROP TABLE IF EXISTS…
2.) CREATE TABLE…
3.) CREATE OR REPLACE FUNCTION…
4.) CREATE TRIGGER…

Und danach kommen mehrere SQL-Anweisungen (INSERT), welche Datensätze in die Tabelle eintragen. Alle Anweisungen werden über ein Statement-Objekt mit execute() zur DB geschickt.

Also, die Datensätze wurden angelegt und die Funktion (welche das Datum für neuangelegte bzw. geänderte Datensätze eintragen soll) scheint auch zu funktionieren.

Klingt so, als hättest Du autocommit eingeschaltet. Ansonsten würde nämlich nach einem Fehler die gesamte Transaktion als fehlerhaft markiert, und keine weiteren Befehle mehr ausgeführt.

Die DB ist Version 8.3. Mit Treiber meinst du wohl den JDBC-Treiber: der ist postgresql-8.4-701.jdbc4.jar

Das passt schon. Ich wollte nur sichergehen.

OK, es scheint wirklich an den Kommentaren gelegen zu haben. Eigentlich logisch. Hab die jetzt rausgenommen und es gibt keine Fehlermeldung mehr. Vielen Dank jedenfalls für deine Hilfe.

Gruss
heyho

Hmm, kenne mich mit PostgreSQL noch nicht so aus. Ich muss mir das mit dem autocommit erst noch mal genauer anschauen. Danke für den Hinweis…