PostgreSQL 9.0.4文書 | ||||
---|---|---|---|---|
前のページ | 巻戻し | 第 42章PL/Python - Python手続き言語 | 早送り | 次のページ |
一般的にいって、PL/Pythonの目標はPostgreSQLとPythonの世界の間で"自然な"対応付けを提供することです。 これは以下のようなデータの対応付けを形成します。
関数引数は、以下のようにPostgreSQLの型から対応するPython型に変換されます。
PostgreSQLのbooleanはPythonのboolに変換されます。
PostgreSQLのsmallintおよびintはPythonのintに変換されます。 PostgreSQLのbigintは、Python 2ではlongに、Python 3ではintに変換されます。
PostgreSQLのreal、doubleおよびnumericはPythonのfloatに変換されます。 numericでは情報が失われ、間違った結果をもたらす可能性があることに注意してください。 将来のリリースでこれは修正されるかもしれません。
PostgreSQLのbyteaは、Python 2ではstrに、Python 3ではbytesに変換されます。 Python 2では文字列は文字符号化方式を持たないバイト列として扱われるはずです。
PostgreSQLの文字列型を含む、上記以外のデータ型はすべてPythonのstrに変換されます。 Python 2ではこの文字列はPostgreSQLのサーバ符号化方式で表されます。 Python 3ではすべての文字列と同様にUnicode文字列となります。
スカラ型以外については後述します。
関数の戻り値は、以下のようにPostgreSQLの宣言された戻り値データ型に変換されます。
PostgreSQLの戻り値の型がbooleanの場合、戻り値はPythonの規約に従った真に対して評価されます。 つまり、0や空文字列は偽です。 'f'が真となることには注意してください。
PostgreSQLの戻り値の型がbyteaの場合、戻り値は文字列(Python 2)またはbytes(Python 3)に、それぞれ対応するPythonのビルトインを使用して変換され、その結果がbyteaに変換されます。
この他のPostgreSQLの戻り値型では、返されるPythonの値はPythonのビルトインstrを使用して文字列に変換され、その結果がPostgreSQLデータ型の入力関数に渡されます。
Python 2における文字列はPostgreSQLに渡される時にPostgreSQLサーバの符号化方式でなければなりません。 現在のサーバ符号化方式で無効な文字列はエラーとなりますが、符号化方式の不一致がすべて検知されることはありません。 このため正確に行われなかった場合にはゴミデータという結果になります。 Unicode文字列は自動的に正しい符号化方式に変換されます。 このためこれを使用することがより安全でより便利です。 Python 3における文字列はすべてUnicode文字列です。
スカラデータ型以外については後述します。
宣言されたPostgreSQLの戻り値型と実際に返されるオブジェクトのPythonデータ型との間の論理的な不整合が伝わらないことに注意してください。 値はいかなる場合でも変換されます。
ティップ: PL/Python関数はRECORD型またはSETOF RECORDを返すことができません。 回避方法は、次のようなPL/pgSQL関数を作成することです。 PL/pgSQL関数で一時テーブルを作成し、その関数からPL/Python関数を呼び出して、一時テーブルに投入し、その後PL/pgSQL関数で一時テーブルから汎用的なRECORDを返します。
SQLのNULL値が関数に渡されると、その引数値はPython.ではNoneとなります。 上の関数定義では、NULL入力では間違った結果が返されます。 関数定義にSTRICTを付与してPostgreSQLを、NULL値が渡された場合にその関数を呼び出さず、自動的に単にNULL結果を返すという、より理想的に動作させることができます。 他に、関数本体でNULL入力を検査することもできます。
CREATE FUNCTION pymax (a integer, b integer) RETURNS integer AS $$ if (a is None) or (b is None): return None if a > b: return a return b $$ LANGUAGE plpythonu;
上で示したように、PL/Python関数からSQL NULL値を返すには、Noneという値を返してください。 関数を厳密とした場合でも厳密としない場合でも、これを行うことができます。
SQL配列値はPythonのリストとしてPL/Pythonに渡されます。 PL/Python関数の外部にSQL配列値を返すためには、Pythonのシーケンス、例えばリストかタプルを返します。
CREATE FUNCTION return_arr() RETURNS int[] AS $$ return (1, 2, 3, 4, 5) $$ LANGUAGE plpythonu; SELECT return_arr(); return_arr ------------- {1,2,3,4,5} (1 row)
Pythonでは、文字列はシーケンスであることに注意してください。 これは予想できない影響を与えることがありますが、Pythonプログラマには慣れたものでしょう。
CREATE FUNCTION return_str_arr() RETURNS varchar[] AS $$ return "hello" $$ LANGUAGE plpythonu; SELECT return_str_arr(); return_str_arr ---------------- {h,e,l,l,o} (1 row)
複合型の引数はPythonのマップとして渡されます。 マップの要素名は複合型の属性名です。 渡された行の属性値がNULLの場合、マップ上ではNoneという値となります。 以下に例を示します。
CREATE TABLE employee ( name text, salary integer, age integer ); CREATE FUNCTION overpaid (e employee) RETURNS boolean AS $$ if e["salary"] > 200000: return True if (e["age"] < 30) and (e["salary"] > 100000): return True return False $$ LANGUAGE plpythonu;
Python関数から行または複合型を返す方法は複数存在します。 以下の例では
CREATE TYPE named_value AS ( name text, value integer );
を前提とします。 複合型の結果は以下のように返されます。
返されるシーケンスオブジェクトは、結果の複合型が持つフィールドと同じ項目数をもたなければなりません。 0というインデックスの項目が複合型の最初のフィールド、1が次のフィールド、、、となります。 以下に例を示します。
CREATE FUNCTION make_pair (name text, value integer) RETURNS named_value AS $$ return [ name, value ] # or alternatively, as tuple: return ( name, value ) $$ LANGUAGE plpythonu;
任意の列でSQL NULL値を返すには、対応する位置にNoneを挿入します。
結果型の列の値は、列名をキーとして持つマップから取り出されます。 以下に例を示します。
CREATE FUNCTION make_pair (name text, value integer) RETURNS named_value AS $$ return { "name": name, "value": value } $$ LANGUAGE plpythonu;
余計な辞書のキーと値の組み合わせは無視されます。 存在しないキーはエラーとして扱われます。 任意の列でSQL NULLを返すためには、対応する列名をキーとしてNoneを挿入してください。
これはマップと同じように動作します。 以下に例を示します。
CREATE FUNCTION make_pair (name text, value integer) RETURNS named_value AS $$ class named_value: def __init__ (self, n, v): self.name = n self.value = v return named_value(name, value) # or simply class nv: pass nv.name = name nv.value = value return nv $$ LANGUAGE plpythonu;
また、PL/Python関数はスカラまたは複合型の集合を返すこともできます。 返されるオブジェクトは内部的にイテレータに変換されるため、複数の実現方法があります。 以下の例では、以下の複合型が存在することを仮定します。
CREATE TYPE greeting AS ( how text, who text );
集合という結果は以下から返されます。
CREATE FUNCTION greet (how text) RETURNS SETOF greeting AS $$ # return tuple containing lists as composite types # all other combinations work also return ( [ how, "World" ], [ how, "PostgreSQL" ], [ how, "PL/Python" ] ) $$ LANGUAGE plpythonu;
CREATE FUNCTION greet (how text) RETURNS SETOF greeting AS $$ class producer: def __init__ (self, how, who): self.how = how self.who = who self.ndx = -1 def __iter__ (self): return self def next (self): self.ndx += 1 if self.ndx == len(self.who): raise StopIteration return ( self.how, self.who[self.ndx] ) return producer(how, [ "World", "PostgreSQL", "PL/Python" ]) $$ LANGUAGE plpythonu;
CREATE FUNCTION greet (how text) RETURNS SETOF greeting AS $$ for who in [ "World", "PostgreSQL", "PL/Python" ]: yield ( how, who ) $$ LANGUAGE plpythonu;
警告 |
Pythonのbug #1483133のため、一部のPython 2.4デバッグ版(--with-pydebugオプション付きで設定/コンパイルされたPython)が、集合結果を返すためにイテレータを使用する場合にPostgreSQLサーバをクラッシュさせることがわかっています。 未パッチのFedora 4にはこの不具合があります。 Python運用版やパッチ適用済みのFedora 4ではこの問題は起こりません。 |