42.3. データ値

一般的にいって、PL/Pythonの目標はPostgreSQLとPythonの世界の間で"自然な"対応付けを提供することです。 これは以下のようなデータの対応付けを形成します。

42.3.1. データ型の対応付け

関数引数は、以下のようにPostgreSQLの型から対応するPython型に変換されます。

関数の戻り値は、以下のようにPostgreSQLの宣言された戻り値データ型に変換されます。

宣言されたPostgreSQLの戻り値型と実際に返されるオブジェクトのPythonデータ型との間の論理的な不整合が伝わらないことに注意してください。 値はいかなる場合でも変換されます。

42.3.2. NullとNone

SQLのNULL値が関数に渡されると、その引数値はPython.ではNoneとなります。 例えば、項42.2に示されたpymax関数の定義では、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という値を返してください。 関数を厳密とした場合でも厳密としない場合でも、これを行うことができます。

42.3.3. 配列、リスト

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)

42.3.4. 複合型

複合型の引数は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
);

を前提とします。 複合型の結果は以下のように返されます。

シーケンス型(タプルまたはリスト。ただしインデック付けができないためset は不可)

返されるシーケンスオブジェクトは、結果の複合型が持つフィールドと同じ項目数をもたなければなりません。 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を挿入してください。

オブジェクト(__getattr__メソッドを提供する任意のオブジェクト)

これはマップと同じように動作します。 以下に例を示します。

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;

OUTパラメータを用いる関数もサポートされています。 以下に例を示します。

CREATE FUNCTION multiout_simple(OUT i integer, OUT j integer) AS $$
return (1, 2)
$$ LANGUAGE plpythonu;

SELECT * FROM multiout_simple();

42.3.5. 集合を返す関数

また、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;

イテレータ(__iter__メソッドとnextメソッドを提供する任意のオブジェクト)

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;

ジェネレータ(yield)

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ではこの問題は起こりません。

RETURNS SETOF recordを使用して)OUTパラメータを持つ集合を返す関数もサポートされます。 以下に例を示します。

CREATE FUNCTION multiout_simple_setof(n integer, OUT integer, OUT integer) RETURNS SETOF record AS $$
return [(1, 2)] * n
$$ LANGUAGE plpythonu;

SELECT * FROM multiout_simple_setof(3);