データ値

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

# 42.3. データ値

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

## 42.3.1. データ型の対応付け

関数引数は、以下のように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`を返します。

## 42.3.2. NullとNone

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

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

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

前のページ | ホーム | 次のページ
PL/Python関数 | 上に戻る | データの共有