PostgreSQL の PL/Python を試してみる

PostgreSQL にはストアドプロシージャ(ファンクション)に PerlPython といったスクリプト言語で記述できる。
これを使えば Perl/Python で外部のサーバにメッセージを飛ばせないかやってみた。


まずは MacPorts で PostgreSQL8.4 をインストール(9.x を使わなかったのには既存の環境が 8.x だったため)。

$ sudo port install postgresql84 +earthdistance +perl +python
$ sudo port install posrgresql84-server
$ sudo port load postgresql84-server
$ sudo mkdir -p /opt/local/var/db/postgresql84/defaultdb
$ sudo chown postgres:postgres /opt/local/var/db/postgresql84/defaultdb
$ sudo su postgres -c '/opt/local/lib/postgresql84/bin/initdb -E UTF-8 --no-locale -D /opt/local/var/db/postgresql84/defaultdb'
$ sudo ln -s /opt/local/lib/postgresql84/bin/pg_ctl /opt/local/bin
$ sudo ln -s /opt/local/lib/postgresql84/bin/postgres /opt/local/bin
$ sudo ln -s /opt/local/lib/postgresql84/bin/psql /opt/local/bin
$ sudo su postgres -c 'pg_ctl -D /opt/local/var/db/postgresql84/defaultdb start'

sample というデータベースを作成し、psql でログインする。

$ psql --host 'localhost' --port 5432 --username 'postgres' 'sample'
psql (8.4.9)
Type "help" for help.

sample=#

PL/Python を利用できるようにする。

sample=# CREATE PROCEDURAL LANGUAGE 'plpythonu' HANDLER plpython_call_handler; 
NOTICE:  using pg_pltemplate information instead of CREATE LANGUAGE parameters
CREATE LANGUAGE

次のような関数を定義する

CREATE OR REPLACE FUNCTION urlpost(IN arg text) RETURNS boolean AS
$$
    import urllib
    url = 'http://localhost:5000/sample/'
    params = urllib.urlencode({'post': arg})
    f = urllib.urlopen(url, params)
    if f.read():
        return True
    return False
$$
LANGUAGE 'plpythonu' VOLATILE;

上記を psql にコピペで登録する。

sample=# CREATE OR REPLACE FUNCTION urlpost(IN arg text) RETURNS boolean AS
sample-# $$
sample$#     import urllib
sample$#     url = 'http://localhost:5000/sample/'
sample$#     params = urllib.urlencode({'post': arg})
sample$#     f = urllib.urlopen(url, params)
sample$#     if f.read():
sample$#         return True
sample$#     return False
sample$# $$
sample-# LANGUAGE 'plpythonu' VOLATILE;
CREATE FUNCTION

これで登録完了。


続いて Web アプリをつくる。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from flask import Flask, render_template, request

app = Flask(__name__)

@app.route('/sample/', methods=['POST'], strict_slashes=False)
def post():
    data = request.form
    app.logger.info(data)

    return 'Success'

if __name__ == '__main__':
    app.debug = True
    app.run(host='localhost', port=5000)

単純に http://localhost:5000/sample/ に POST があればログを吐いて Success を返すだけ。
psql で次のように呼び出す。

sample=# select urlpost('sample');
 urlpost 
---------
 t
(1 row)

Python 側のログ

$ python app.py
 * Running on http://localhost:5000/
 * Restarting with reloader
--------------------------------------------------------------------------------
INFO in app [app.py:24]:
ImmutableMultiDict([('post', u'sample')])
--------------------------------------------------------------------------------
127.0.0.1 - - [06/Oct/2011 22:23:10] "POST /sample/ HTTP/1.0" 200 -

というわけで無事に外部にメッセージを送信する事が出来た。
PostgreSQL すげー。