2016-08-29 1 views
1

Für meine Hi/Lo-Implementierung benötige ich eine Funktion, die exklusive Tabellensperre erhält, Wert aktualisiert und eine Zeile auswählt. Ich kam mit dem folgenden Code auf:Postgresql-Funktion, die Tabelle sperrt, Wert aktualisiert und Zeile zurückgibt

CREATE OR REPLACE FUNCTION bb_next_hi(tbl varchar(35)) 
RETURNS setof record AS 
$$ 
    LOCK TABLE hilo IN ACCESS EXCLUSIVE MODE; 
    OPEN ref FOR SELECT hi as "Hi", lo as "Lo", "table" as "Table" FROM hilo WHERE "table" = $1; 
    UPDATE hilo SET hi = hi + 1 WHERE "table" = $1 
    RETURN ref; 

$$ LANGUAGE plpgsql; 

Wenn jedoch die Funktion aufgerufen wird, gibt sie keine Zeile, sondern eine Säule mit einem Inhalt ähnlich dem „unnamed Portal 3“. Ich denke, ich sollte über zurückgegebene Ref (aber wie) iterieren?

Ein anderer Ansatz, den ich verwenden könnte, ist, UPDATE RETURNING-Anweisung zu verwenden, aber ich bin mir nicht sicher, ob Race-Bedingungen in diesem Fall auftreten können. Jede Hilfe wäre willkommen. Dank

+0

Warum sperren Sie die gesamte Tabelle, wenn Sie nur eine einzelne Zeile sperren möchten? –

+0

Ich denke, es gibt keine andere Möglichkeit, Leser zu sperren. Vielleicht irre ich mich und missverstand etwas, wäre für eine Erklärung gut, wenn das so wäre :) – Davita

Antwort

1

Sie verwenden eine cursor Variable (die Sie nicht deklariert haben und einige andere PL/pgSQL erforderliche Elemente auch fehlen) und Sie geben das zurück. Cursorreferenzen werden in der Tat als "Portale" bezeichnet, was Ihre Ausgabe erklärt. Ein besserer Ansatz ist das:

CREATE OR REPLACE FUNCTION bb_next_hi(tbl varchar(35)) 
RETURNS TABLE ("Hi" int, "Lo" int, "Table" varchar(35)) AS $$ 
BEGIN 
    LOCK TABLE hilo IN ACCESS EXCLUSIVE MODE; 
    RETURN QUERY SELECT hi, lo, $1 FROM hilo WHERE "table" = $1; 
    UPDATE hilo SET hi = hi + 1 WHERE "table" = $1; 
    RETURN; 
END; 
$$ LANGUAGE plpgsql STRICT; 

Aber brauchen Sie wirklich ein exklusives Schloss auf dem Tisch? Es gibt viel weniger invasive Ansätze, um einen konsistenten Tabellen-Snapshot zu erhalten.

2

Das scheint mir viel einfacher:

CREATE OR REPLACE FUNCTION bb_next_hi(tbl varchar(35)) 
RETURNS setof record AS 
$$ 
BEGIN 
    LOCK TABLE hilo IN ACCESS EXCLUSIVE MODE; 
    RETURN QUERY UPDATE hilo SET hi = hi + 1 WHERE "table" = $1 
     RETURNING hi as "Hi", lo as "Lo", "table" as "Table"; 
END; 
$$ LANGUAGE plpgsql; 

ich in der Regel auch RETURNS TABLE (col1 varchar, col2 varchar...) statt RETURNS setof record definieren.

+0

Dies gibt den aktualisierten Wert von "hi" zurück, anders als das, was das OP versucht hat zu bekommen. – Patrick

+0

Das stimmt, daran habe ich nicht gedacht. Im Falle von + = 1 sollte es jedoch kein großes Problem darstellen. –

Verwandte Themen