Contents


怖いと言っても「ある種のPL/Rストアド関数を作り、NULLを渡す」クエリ。PL/Rの入ってないPostgreSQLサーバには無関係です。

「古いバージョンで」というのもPL/Rの方。ただし正確には、今年3月以前のソースでビルドされたもの全てが該当し、パッケージ版の最新8.3.0.16でもPostgreSQLサーバが落ちます…。

開発側は当然分かっていて、修正に伴う確認用クエリを追加しただけと思いますが、現時点ではコミット履歴を見ないとそのことが分かりません。何気なく「テストクエリがあるから実行してみよ~」とかやると危険なので、以下メモ。


問題のクエリを含むplr.sql

下記です。今年330日が直近の修正で、そのコメントにfix: issue#2 server process terminated when argument is null to as.numeric(NULL)と。

» github.com/jconway/plr/blob/master/sql/plr.sql

35行目以降が追加部分
(詳細はコミット履歴で)。例えば先頭は ↓ こうなってて、NULLを渡すクエリを従前のPL/Rで実行するとPostgreSQLが即座に落ちます。
--
-- test simple input/output types
--

CREATE OR REPLACE FUNCTION rint2(i int2) RETURNS int2 AS $$ 
return (as.integer(i))
$$ LANGUAGE plr;
select rint2(1::int2);
select rint2(NULL);  -- Postgres crashes on previous PL/R. 


修正されたのはpg_conversion.c。従前のPL/Rでも、関数内でNULLを直接as.interger等に突っ込まないようにすれば ↓ 一応回避できます。
# CREATE OR REPLACE FUNCTION rint2_rev(i int2) RETURNS int2 AS $$ 
  if (! is.null(i)) return (as.integer(i))
  $$ LANGUAGE plr;

# select rint2_rev(1::int2);
+-----------+
| rint2_rev |
+-----------+
|         1 |
+-----------+
(1 row)

# select rint2_rev(NULL);
+-----------+
| rint2_rev |
+-----------+
|           |
+-----------+
(1 row)

上記の実行環境はScientific Linux 7.0 + PostgreSQL 9.5.3 + PL/R 8.3.0.16。


share/extension内にあるplr.sqlとは別

ややこしい。問題のSQLファイルは「テスト用の付属物」ですが同名のplr.sqlがソース内にあり、こちらはCREATE EXTENSIONに使われるシステム上のファイル。上記の実行環境では ↓ ここに入ってます。
$ ls /usr/pgsql-9.5/share/extension/plr*

/usr/pgsql-9.5/share/extension/plr--8.3.0.16.sql
/usr/pgsql-9.5/share/extension/plr--unpackaged--8.3.0.16.sql
/usr/pgsql-9.5/share/extension/plr.control
/usr/pgsql-9.5/share/extension/plr.sql


実際のサーバクラッシュ時

どんなエラーが出るかの記録として。クライアント側では ↓ サーバとの接続が突然切れたことしか分かりません。その下がサーバのログ。
-- source of the function
# \sf public.rint2
CREATE OR REPLACE FUNCTION public.rint2(i smallint)
 RETURNS smallint
 LANGUAGE plr
AS $function$
return (as.integer(i))
$function$

-- query to terminate server
# select rint2(NULL);
server closed the connection unexpectedly
        This probably means the server terminated abnormally
        before or while processing the request.
The connection to the server was lost. Attempting reset: Failed.

$ cat $PGDATA/pg_log/postgresql-Tue.log

Error: CHAR() can only be applied to a 'CHARSXP', not a 'logical'
*** stack smashing detected ***: postgres: postgres test_plr [local] SELECT terminated
< 2016-07-19 08:48:09.664 JST >LOG:  server process (PID 12699) was terminated by signal 11: Segmentation fault
< 2016-07-19 08:48:09.664 JST >DETAIL:  Failed process was running: select rint2(NULL);
< 2016-07-19 08:48:09.664 JST >LOG:  terminating any other active server processes
< 2016-07-19 08:48:09.665 JST >WARNING:  terminating connection because of crash of another server process
< 2016-07-19 08:48:09.665 JST >DETAIL:  The postmaster has commanded this server process to roll back the current transaction and exit, because another server process exited abnormally and possibly corrupted shared memory.
< 2016-07-19 08:48:09.665 JST >HINT:  In a moment you should be able to reconnect to the database and repeat your command.
< 2016-07-19 08:48:09.666 JST >LOG:  all server processes terminated; reinitializing
< 2016-07-19 08:48:09.676 JST >LOG:  database system was interrupted; last known up at 2016-07-19 08:31:26 JST
< 2016-07-19 08:48:09.771 JST >LOG:  database system was not properly shut down; automatic recovery in progress
< 2016-07-19 08:48:09.772 JST >LOG:  invalid record length at 0/1805348
< 2016-07-19 08:48:09.772 JST >LOG:  redo is not required
< 2016-07-19 08:48:09.775 JST >LOG:  MultiXact member wraparound protections are now enabled
< 2016-07-19 08:48:09.778 JST >LOG:  database system is ready to accept connections
< 2016-07-19 08:48:09.778 JST >LOG:  autovacuum launcher started


というわけでPL/Rのパッケージが早く更新されるといいけど、その前に自分でビルドできればベター。と思って
先日来のMSYS2 + MinGW-w64環境でやろうとしたら、先にRのビルドが必要で面倒だな~と足踏み中です。