PL/Python関数

PostgreSQL 8.4.1文書
前のページ | 巻戻し | 第 41章PL/Python - Python手続き言語 | 早送り | 次のページ

# 41.1. PL/Python関数

PL/Pythonで作成された関数は標準のCREATE FUNCTION構文で宣言されます。

    CREATE FUNCTION funcname (argument-list)
      RETURNS return-type
    AS $$
      # PL/Python function body
    $$ LANGUAGE plpythonu;

関数本体は単なるPythonスクリプトです。 関数が呼び出されると、引数は`args[]`配列の要素として、また、名前付きの引数は通常の変数としてPythonスクリプトに渡されます。 結果は、Pythonコードから通常の方法、`return`または`yield`（結果セット文の場合）で返されるものです。

たとえば、2つの整数の内大きな数を返す関数は以下のように定義することができます。

    CREATE FUNCTION pymax (a integer, b integer)
      RETURNS integer
    AS $$
      if a > b:
        return a
      return b
    $$ LANGUAGE plpythonu;

関数定義の本体として提供されたPythonのコードはPythonの関数に変換されます。 例えば上の例は以下のようになります。

    def __plpython_procedure_pymax_23456():
      if a > b:
        return a
      return b

ここで、23456はPostgreSQLにより割り当てられたこの関数のOIDです。

PostgreSQL関数パラメータは`args`グローバルリストから利用可能です。 `pymax`を例にすると、`args[0]`には最初の引数として渡されたものが含まれ、`args[1]`には2番目の引数の値が含まれます。 別の方法として、上の例のように名前付きパラメータを使用することができます。 名前付きパラメータを使用することで通常可読性が増します。

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`という値を返してください。 関数を厳密とした場合でも厳密としない場合でも、これを行うことができます。

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

戻り値を用意していない場合、Pythonはデフォルトの`None`を返します。 PL/Pythonは、Pythonの`None`をSQLのNULL値に変換します。

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

グローバルな`SD`辞書は、関数呼び出し間のデータ保存のために使用することができます。 この変数はプライベートな静的データです。 グローバルな`GD`辞書は、共有データであり、セッション内の全てのPython関数で使用することができます。 注意して使用してください。

各関数は、Pythonインタプリタ内で自身の実行環境を入手します。 そのため、`myfunc`によるグローバルデータと関数の引数は`myfunc2`から使用することはできません。 上記で説明した通り、`GD`辞書内のデータは例外です。

前のページ | ホーム | 次のページ
PL/Python - Python手続き言語 | 上に戻る | トリガ関数