PostgreSQLには、無名関数用のDOというSQLコマンドがあります(ドキュメントでは「無名コードブロック」という呼称)。通常のストアド関数が、名前と置き場所を決めて保存してから使うのに対し、こちらは一時的に、PL/pgSQLPL/Pythonなどの組み込み言語で無名関数を書いて実行できます。引数や戻り値のやり取りはできませんが、SQLでは面倒or難しい処理を手軽に混ぜたり、クエリツール上でテストするには便利。

ただしPL/RはこのDOコマンドに対応してなく、簡単なRのコードを試すにもいったんストアド関数化が必要です。でも、せっかくWindows版で日本語が使えると分かり(521日の記事参照)活用範囲が広がりそうなので、代替的な関数plr_doを作りました。↓ が実行例で、引数にRのコードをまるごと文字列として渡し、出力(ここではprint文の結果)がメッセージ欄に出ます。実行環境はWindows 7 32bit + PostgreSQL Portable 9.4 + R 3.1.2 + PL/R 8.3.0.16。


ソースコードと使用例
今回はtestというスキーマを作って作業しましたが(publicスキーマにPL/Rのシステム的な関数があるので、それと分けた)、動作上はどこに置いても同じ。ソースは ↓ の最初の10行程度のごく短いもので、引数で渡された文字列をparseevalで評価し、出力をcapture.outputで捕捉しています。ソースの次、Example 1が上の例。

念のためtryで実行結果の正常/エラーを分け、前者なら結果をPostgreSQLNOTICEとして返します。最後のpg.throw~の2つの関数のみ、R本体にないPL/R専用の関数。詳細は
PL/R User's Guide - 6.1. Normal Supportにあります。
CREATE OR REPLACE FUNCTION test.plr_do(text)
RETURNS void LANGUAGE plr IMMUTABLE AS $$
try = try ( {
    p = parse(text = arg1)
    e = eval(p)
    cap = capture.output (e)
}, silent=T)

if (inherits(try, 'try-error')) {
    pg.throwerror(try[1])
} else {
    for (m in cap) pg.thrownotice (m)
}
$$;

-- Example 1
DO $$
BEGIN
PERFORM test.plr_do('
    options(show.signif.stars = F)
    x = runif(100)
    y = runif(100)
    model = lm(y ~ x)
    print(summary(model))
');
END $$;

-- Example 2
-- Show blank output first (useless)
SELECT test.plr_do('
    x = runif(100)
    y = runif(100)
    model = lm(y ~ x)
    print(summary(model))
');

-- Example 3
-- with error
DO $$
BEGIN
PERFORM test.plr_do('
    x = rand(100)
    y = rand(100)
    model = lm(y ~ x)
    print(summary(model))
');
END $$;

Example 2の実行結果。1では関数をDO構文の中で実行したのに対し、ここではSELECT文で直接実行しました。pgAdminのクエリツールを使う場合、実行直後にどのペインを開くかが違います。DOはメッセージ、SELECTはデータアウトプットで、後者だと ↓ のように空の結果がまず示され、実行内容を確認するには手動でメッセージ欄を開く必要が生じます。Rで行う処理が表示結果を持たない(データを変換し保存するとか)ならこれでもよく、そうでなければ少し記述が増えますがExample 1の方が便利です。

下はExample 3で、Rのコードを間違えた場合。エラー情報のうちDETAILが、R本体が発行した内容です。エラーをRの中だけに留めてこの関数自体は常に正常終了させることも可能ですが(tryの後処理を変えればいい)、前後に別のSQLを組み合わせる場合を考え、今回はこうしました。