web-dev-qa-db-ja.com

ドロップされた(または変更された)関数は、すでに開いているトランザクション内で引き続き使用できますか?

見つけた

しかし、答えはなく、私の質問とまったく同じではありません(非常に類似しています)。


私が次のことをするとしましょう:

  1. 関数を作成するmyfunc()
  2. クライアントAからトランザクションを開始する
  3. クライアントBからトランザクションを開始する
  4. トランザクションBで、「関数の作成または置換」を使用してmyfunc()の定義を修正します
  5. トランザクションBをコミットする
  6. トランザクションAからmyfunc()を呼び出す

ステップ6で何が起こりますか?ステップ1で定義された元の関数を呼び出していますか?または、ステップ4から変更されたフォーム(ステップ5でコミット)?


また、関数が変更されるのではなく、手順4で削除された場合、手順6は失敗するか成功しますか? (これはおそらく同じ質問ですが、変更が異なる場合があります。)


これに関するドキュメントはどこにありますか?

7
Wildcard

ステップ6では何が起こりますか?

トランザクションAは、関数myfunc()の更新された定義をすぐに確認します。 (ただし、以下のキャッシュの影響を参照してください。)

また、関数が変更されるのではなく、手順4で削除された場合、手順6は失敗するか成功しますか?

失敗します。 (ただし、以下のキャッシュの影響を参照してください。)

Postgres DDLコマンドは完全にトランザクションです。トランザクションBはコミットしませんが、両方のトランザクションで引き続き異なるバージョンの関数が表示されます。しかし、同時トランザクションdo参照committedシステムカタログの変更。デフォルトの分離レベルREAD COMMITTED。しかし、これを分離レベルで防ぐことはできませんREPEATABLE READまたはSERIALIZABLE

IfトランザクションBが変更をコミットする前に、トランザクションAで関数を呼び出し、ローカルcacheが干渉する可能性があります。私のテストでは、次の呼び出しが変更を認識する前に、キャッシュされた(古い)関数でone呼び出しが機能しましたそれに応じて答えた。

システムカタログキャッシュがこのためにどのように動作するかについてのドキュメントは見つかりませんでした(まだどこかに存在している可能性があります)。私は最後のビット(キャッシュから返されたもう1つのコール)が最良の動作であるとは確信していません。


ところで、あなたのステップ3.-5.は、違いなく、ちょうど4.に減らすことができます。明示的または暗黙的なトランザクションラッパーは同じように機能します。

3.クライアントBからトランザクションを開始します
4。トランザクションBで、「関数の作成または置換」を使用して、myfunc()の定義を修正します。
5.トランザクションBをコミットします。

4

興味深い質問です。

小さなテストから、関数の変更と削除はトランザクションであるように見えます。つまり、分離レベルでは、トランザクション2が関数を変更または削除しても、トランザクション1はそれを認識せず、古いバージョンの関数を使用します。

関数への変更は、トランザクションがコミットされた後でのみ、およびそのコミット後に開始されたトランザクションにのみ表示されます。テストされた関数がどのテーブルからもデータを読み取っていなかったため、分離レベルは無関係です。

-- 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=# 

少し異なるシナリオでは、両方のトランザクションが関数を変更しようとすると、一方のみが成功し、もう一方はブロックされ、最初のコミットが失敗します。

6
ypercubeᵀᴹ