データベースアクセス

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

# 42.7. データベースアクセス

PL/Python言語モジュールは自動的に`plpy`というPythonモジュールをインポートします。 このモジュールの関数と定数は、`plpy.`foo``のように作成したPythonコードから使用することができます。

## 42.7.1. データベースアクセス関数

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

以下に例を示します。

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

これは、`my_table`から5行までを返します。 `my_table`に`my_column`列が存在する場合、その列には以下のようにアクセスできます。

    foo = rv[i]["my_column"]

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)

3番目の引数は制限引数であり、省略可能です。

問い合わせパラメータおよび結果行のフィールドは項42.3で示した通り、PostgreSQLとPythonのデータ型の間で変換されます。 現在複合型がサポートされていないという例外があります。 複合型は問い合わせパラメータとしては拒絶され、問い合わせの結果に存在する場合は文字列に変換されます。 後者の問題の回避方法として、結果行のフィールドとしてではなく結果行として複合型が存在するように問い合わせを書き換えることができる場合があります。 他に、結果として生じる文字列を手作業で解析して分離することもできますが、この方法は時代に左右されてしまいますので推奨されません。

PL/Pythonモジュールを使用して準備した計画は自動的に保存されます。 これが何を意味するのかについてはSPIの文書（第43章）を参照してください。 これを複数呼び出しにおいて効果的に使用するためには、永続的な格納用辞書である`SD`または`GD`（項42.4を参照）のいずれかを使用する必要があります。 例えば、以下のようにします。

    CREATE FUNCTION usesavedplan() RETURNS trigger AS $$
        if SD.has_key("plan"):
            plan = SD["plan"]
        else:
            plan = plpy.prepare("SELECT 1")
            SD["plan"] = plan
        # rest of function
    $$ LANGUAGE plpythonu;

## 42.7.2. エラーの捕捉

データベースにアクセスする関数はエラーに遭遇し、エラーが関数をアボートして例外を発生させる原因となります。 `plpy.execute`および`plpy.prepare`は、デフォルトでは関数を終了させる`plpy.SPIError`のサブクラスのインスタンスを発生させることができます。 このエラーは、`try/except`構文を使用して、Pythonの他の例外と同様に処理できます。 例を示します。

    CREATE FUNCTION try_adding_joe() RETURNS text AS $$
        try:
            plpy.execute("INSERT INTO users(username) VALUES ('joe')")
        except plpy.SPIError:
            "うまくいかなかった" を返す
        else:
            "Joeが追加された" を返す
    $$ LANGUAGE plpythonu;

発生される例外の実クラスはエラーを引き起こした特定の条件と対応します。 表A-1にあり得る条件のリストがありますので参照してください。 `plpy.spiexceptions`モジュールはPostgreSQLの条件それぞれに対して、その条件名に因んだ名前の例外クラスを定義しています。 例えば`division_by_zero`は`DivisionByZero`、`unique_violation`は`UniqueViolation`に、`fdw_error`は`FdwError`などのようになります。 これらの例外クラスはそれぞれ`SPIError`を継承したものです。 このように分離することで特定のエラーをより簡単に扱うことができるようになります。 以下に例を示します。

    CREATE FUNCTION insert_fraction(numerator int, denominator int) RETURNS text AS $$
    from plpy import spiexceptions
    try:
        plan = plpy.prepare("INSERT INTO fractions (frac) VALUES ($1 / $2)", ["int", "int"])
        plpy.execute(plan, [numerator, denominator])
    except spiexceptions.DivisionByZero:
        return "denominator cannot equal zero"
    except spiexceptions.UniqueViolation:
        return "already have that fraction"
    except plpy.SPIError, e:
        return "other error, SQLSTATE %s" % e.sqlstate
    else:
        return "fraction inserted"
    $$ LANGUAGE plpythonu;

`plpy.spiexceptions`モジュールからの全ての例外は`SPIError`を継承するため、例外を処理する`except`句は全てのデータベースアクセスエラーを捕捉することに注意してください。

異なったエラー条件を処理する代りの方法として、`SPIError`例外を捕捉して、例外オブジェクトの`sqlstate`属性を調べることにより、`except`ブロック内部の明細なエラー条件を決定できます。 この属性は"SQLSTATE"エラーコードを含む文字列値です。 この方法は、ほぼ同じ機能を提供します。

前のページ | ホーム | 次のページ
トリガ関数 | 上に戻る | 明示的サブトランザクション