Ist in bereits geöffneten Transaktionen noch eine gelöschte (oder geänderte) Funktion verfügbar?

7

ich fand

aber es gibt keine Antworten und ist nicht genau das gleiche wie meine Frage (obwohl sehr ähnlich).


Angenommen, ich mache Folgendes:

  1. Erstellen Sie eine Funktion myfunc()
  2. Starten Sie eine Transaktion von Client A.
  3. Starten Sie eine Transaktion von Client B.
  4. Verwenden Sie in Transaktion B "Funktion erstellen oder ersetzen", um die Definition von zu überarbeiten myfunc()
  5. Transaktion festschreiben B.
  6. Anruf myfunc()von Transaktion A.

Was passiert in Schritt 6? Rufe ich die ursprüngliche Funktion auf, wie in Schritt 1 definiert? Oder das geänderte Formular aus Schritt 4 (festgeschrieben in Schritt 5)?


Und wenn die Funktion in Schritt 4 gelöscht wird, anstatt geändert zu werden, wird Schritt 6 fehlschlagen oder erfolgreich sein? (Dies ist wahrscheinlich die gleiche Frage, aber Änderungen können anders funktionieren.)


Wo ist die Dokumentation dazu?

Platzhalter
quelle

Antworten:

4

Was passiert in Schritt 6?

Transaktion A sieht myfunc()sofort die aktualisierte Definition der Funktion . (Aber sehen Sie den Effekt des Caches unten.)

Und wenn die Funktion in Schritt 4 gelöscht wird, anstatt geändert zu werden, wird Schritt 6 fehlschlagen oder erfolgreich sein?

Es wird scheitern. (Aber sehen Sie den Effekt des Caches unten.)

Postgres-DDL-Befehle sind vollständig transaktional. Während Transaktion B nicht festgeschrieben wird, werden für beide Transaktionen weiterhin unterschiedliche Versionen der Funktion angezeigt. Aber gleichzeitig ablaufenden Transaktionen tun sehen engagierte Änderungen in Systemkatalogen. In der Standardisolationsstufe scheint dies offensichtlich zu sein READ COMMITTED. Aber Sie können dies nicht einmal mit Isolationsstufen REPEATABLE READoder verhindern SERIALIZABLE.

Wenn Sie die Funktion in Transaktion A aufgerufen haben sollten, bevor Transaktion B eine Änderung festgeschrieben hat, kann der lokale Cache stören. In meinen Tests arbeitete ein weiterer Anruf mit der zwischengespeicherten (alten) Funktion, bevor der nächste Anruf die Änderung bemerkte und entsprechend antwortete.

Ich habe keine Dokumentation gefunden, wie sich der Systemkatalog-Cache genau dafür verhält (möglicherweise noch irgendwo vorhanden). Ich bin nicht davon überzeugt, dass das letzte Bit (ein weiterer Anruf aus dem Cache beantwortet) das bestmögliche Verhalten ist.


Übrigens können Ihre Schritte 3. - 5. ohne Unterschied auf nur 4. reduziert werden. Explizite oder implizite Transaktions-Wrapper funktionieren genauso:

3. Starten Sie eine Transaktion von Client B aus.
4. Verwenden Sie in Transaktion B die Funktion "Erstellen oder Ersetzen", um die Definition von myfunc () zu überarbeiten.
5. Übernehmen Sie Transaktion B.

Erwin Brandstetter
quelle
Großartig! Wenn also Schritt 5 weggelassen wird und Schritt 4 weggelassen oder die Funktion geändert wurde, wird Schritt 6 erfolgreich sein und die Originalversion ausführen, um mein Verständnis zu überprüfen.
Wildcard
1
@Wildcard: Wenn Sie Schritt 3 ( BEGIN;) haben, aber nicht Schritt 5 ( COMMIT;) Ihre Änderung, ob für eine andere Transaktion als Transaktion B sichtbar DROPoder REPLACEnie sichtbar ist. Sie müssen dies jedoch COMMIToder ROLLBACKfrüher oder später tun. Besser früher als später sollte der Leerlauf in der Transaktion nicht zu lange
Erwin Brandstetter
Vielen Dank; Der Punkt, dass er für keine andere Transaktion sichtbar ist, mag offensichtlich erscheinen, aber die Ausnahme für TRUNCATE hat mich unsicher gemacht.
Wildcard
6

Interessante Frage.

Aus einem kleinen Test geht hervor, dass Funktionsänderungen und -löschungen transaktional sind. Dies bedeutet, dass - in jeder Isolationsstufe - wenn Transaktion 2 die Funktion ändert oder löscht, Transaktion 1 diese nicht wahrnimmt und weiterhin die alte Version der Funktion verwendet.

Änderungen an der Funktion werden erst nach dem Festschreiben der Transaktion und nur für Transaktionen sichtbar, die nach diesem Festschreiben beginnen. Die Isolationsstufe ist irrelevant, da die getestete Funktion keine Daten aus Tabellen las.

-- Create Function
x=# create or replace function f() returns integer as
$$ select 1 ; $$ immutable language sql ;
CREATE FUNCTION

-- TRAN 1
x=# begin ;
BEGIN
x=# select * from f() ;
 f 
---
 1
(1 row)
                    -- TRAN 2
                    x=# begin ;
                    BEGIN
                    x=# drop function f () ;
                    DROP FUNCTION
                    x=# commit ;
                    COMMIT
-- TRAN 1
x=# select * from f() ;
 f 
---
 1
(1 row)
x=# commit ;
COMMIT

-- After COMMIT
x=# select * from f() ;
ERROR:  function f() does not exist
LINE 1: select * from f() ;
                      ^
HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
x=# 

Wenn in einem etwas anderen Szenario beide Transaktionen versuchen, die Funktion zu ändern, ist nur eine erfolgreich und die andere wird blockiert und schlägt fehl, wenn die erste festgeschrieben wird.

ypercubeᵀᴹ
quelle
2
Ich stimme der Schlussfolgerung nicht zu. Wenn Sie den ersten select * from f()im festgeschriebenen Lesemodus aus TRAN1 entfernen, select * from f()schlägt der zweite fehl. Der obige Test scheint den Effekt eines lokalen Suchcaches für TRAN1 zu demonstrieren und nicht das, was Sie in der Antwort schließen.
Daniel Vérité
@ DanielVérité Ich habe verschiedene Dinge ausprobiert, einschließlich dessen, was du sagst, in allen Isolationsstufen. Es war egal. Sind Sie nicht einverstanden mit dem ersten Teil (oder dem zweiten über beide
Transmodifikationen
@ DanielVérité hast du mit einer anderen Funktion getestet (bei der aus Tabellen gelesen wurde)?
Ypercubeᵀᴹ
Genau der gleiche Test wie Sie, kopiert aus der Antwort, PG 10, alle Standardeinstellungen, außer dass TRAN1 nichtselect * from f() aufgerufen wird, bevor die Funktion in der anderen Transaktion gelöscht wird.
Daniel Vérité
Seltsam. Ich verstehe, was Sie sagen, nur wenn ich eine Lesedatenfunktion (Postgres 9.6) verwende, werde ich auch in 10 weitere Tests durchführen und die Antwort bearbeiten.
Ypercubeᵀᴹ