【JPUG主催】PostgreSQLカンファレンス2020【11月13日開催】
他のバージョンの文書 12 | 11 | 10 | 9.6 | 9.5 | 9.4 | 9.3 | 9.2 | 9.1 | 9.0 | 8.4 | 8.3 | 8.2 | 8.1 | 8.0 | 7.4 | 7.3 | 7.2

26.3. PL/Python の使用

plpython_function.sql に関数のサンプルがあります。作成した Python のコードは関数に変換されます。例えば、

CREATE FUNCTION myfunc(text) RETURNS text AS
'return args[0]'
LANGUAGE 'plpython';

は、以下のように変換されます。

def __plpython_procedure_myfunc_23456():
	return args[0]

ここで、23456 はこの関数の OID です。

戻り値を用意していない場合、Python は不要かもしれない、デフォルトの None を返します。この言語モジュールは Python の None を SQL の NULL に変換します。

PostgreSQL 関数の変数はグローバルな args リスト内で使用することができます。上の myfunc では args[0] には、渡されたものがテキスト引数として格納されています。 myfunc2(text, integer) の場合は、 args[0] には text 変数が、 args[1] には integer 変数が格納されます。

グローバルな SD 辞書は、関数呼び出し間のデータ保存のために使用することができます。この変数はプライベートな静的データです。グローバルな GD 辞書はパブリックなデータであり、バックエンド内の全ての python 関数から使用することができます。注意して使用して下さい。

各関数は、Python インタプリタ内で自身の制限された実行オブジェクトを入手します。そのため、myfunc によるグローバルデータと関数の引数は myfunc2 から使用することはできません。上で説明したとおり、GD 辞書内のデータは例外です。

トリガ内で関数を使用した場合、TD 辞書にトランザクションに関係した値が格納されます。トリガのタプルはトリガイベントに応じて、TD["new"]TD["old"] のどちらかまたは両方に格納されます。 TD["event"] には、(INSERT, UPDATE, DELETE, または UNKNOWN という)文字列としてイベントが格納されます。TD["when"] には、BEFORE, AFTER, または UNKNOWN)のいずれかが格納されます。 TD["level"] には ROW, STATEMENT, または UNKNOWNのいずれかが格納されます。TD["name"] にはトリガの名前が、TD["relid"] にはトリガの発生元テーブルのリレーション ID が格納されます。トリガが引数付きで呼び出された場合、その引数は TD["args"][0] to TD["args"][(n -1)] として使用することができます。

トリガの "when"BEFORE の場合、 Python の関数から、タプルが変更されないことを示す、None または "OK" を返すことも、イベントを中断したことを示す、 "SKIP" を返すことも、タプルを変更したことを示す、 "MODIFIED" を返すこともできます。

PL/Python 言語モジュールは自動的に plpy Python モジュールをインポートします。このモジュールの関数と定数は、 plpy.foo のように作成した Python コードから使用することができます。現在の plpyplpy.error("msg"), plpy.fatal("msg"), plpy.debug("msg"), および、 plpy.notice("msg") を実装しています。これらは elog(LEVEL, "msg") の呼び出しとほぼ同じです。ここで LEVEL は DEBUG, ERROR, FATAL または NOTICE です。 plpy.errorplpy.fatal は実際、Python の例外を発生します。これが catch されない場合、PL/Python はその関数ハンドラが Python インタプリタから返る時に、elog(ERROR, msg) を呼び出します。Python インタプリタからの long jump はおそらく良くありません。 raise plpy.ERROR("msg")raise plpy.FATAL("msg") はそれぞれ、 plpy.errorplpy.fatal の呼び出しと同じです。

更に、plpy モジュールは execute および prepare という2つの関数を用意しています。 plpy.execute を問い合わせ文字列、省略可能な制限引数を付けて呼び出すと、問い合わせが実行され、結果オブジェクトとして問い合わせ結果が返ります。この結果オブジェクトはリストもしくは辞書オブジェクトを模擬します。結果オブジェクトは行番号やフィールド名によってアクセスすることができます。結果オブジェクトには、問い合わせ結果の行数を返す nrows()SPI_exec が返す変数である、status というメソッドが追加されています。

rv = plpy.execute("SELECT * FROM my_table", 5)

は my_table から 5 行までを返します。my_table が my_field 列を持っているとすると、その列には以下のようにアクセスできます。

foo = rv[i]["my_field"]

2 番目の関数 plpy.prepare は問い合わせ文字列と、問い合わせ内の変数にバインドさせる引数型のリストを付けて呼び出されます。

plan = plpy.prepare("SELECT last_name FROM my_users WHERE first_name = $1", [ "text" ])

text は $1 として今後渡す変数の型です。準備を行なったあとに、plpy.execute 関数を使用して実行することができます。

rv = plpy.execute(plan, [ "name" ], 5)

制限引数は plpy.execute を呼び出す時に省略することができます。

PL/Python モジュールを使用して準備した計画は自動的に保存されます。これが何を意味するのかについては SPI の文書 (Chapter 21) を参照して下さい。最後に、私は保存した計画の解放方法が分からないので、

plan = plpy.prepare("SOME QUERY")
plan = plpy.prepare("SOME OTHER QUERY")

を行なった場合、メモリリークが起こります。代替案は、保存なし計画を使用することですが、(私にとって)より困難なことです。