bytea
型の列を持つpostgresqlデータベースにテーブルがあります。ファイル名としてidを使用して、各バイナリエントリをファイルとしてドロップしたいと思います。
この場合、SQLクエリはどのようになりますか?
Byteaをディスクサーバー側に保存するには、データベースのスーパーユーザーである必要があります。通常のユーザーはファイルシステムへの書き込みを許可されていません。
スーパーユーザー権限を想定すると、最も簡単な方法は、「信頼されていない」言語の1つで関数として実装することです。
CREATE FUNCTION bytea_to_file(bytea,text) RETURNS void AS $$
open(my $fd, ">".$_[1]) or die $!;
binmode($fd);
print $fd decode_bytea($_[0]);
close($fd);
$$ language plperlu;
使用法:
select bytea_to_file(bytea_column, concat('/path/to/destination/', id_column))
from tablename where...
そのような言語がpostgres環境で利用できない場合、非効率的なバージョンがpl/pgsqlに作成される可能性があります。ファイルとしてエクスポートする前に一時的なラージオブジェクトを作成し、データ全体をコピーしてから、ラージオブジェクトを削除する必要があるため、非効率的です。
CREATE FUNCTION bytea_to_file_with_lo(bytea,text) RETURNS void AS $$
declare
o oid;
fd integer;
INV_WRITE int := 131072;
begin
o:=lo_create(-1);
fd:=lo_open(o, INV_WRITE);
if (fd<0) then
raise exception 'Failed to open large object %', o;
end if;
perform lowrite(fd, $1);
if (lo_close(fd)<>0) then
raise exception 'Failed to close large object %', o;
end if;
perform lo_export(o, $2);
perform lo_unlink(o);
end;
$$ language plpgsql;
使用法:pl/perluバージョンと同じ。この関数のスーパーユーザー権限が他のユーザーにのみ付与されている場合を除いて、スーパーユーザーである必要があります(この場合、この場合はユーザーを100%信頼しているの場合のみ問題ありません。それ以外の場合は悲惨です)。
alter FUNCTION bytea_to_file_with_lo(bytea,text) SECURITY DEFINER;
自由に使用できるのがクライアント側のpsql
インタープリターである場合、バイナリコンテンツを直接抽出することはできません(結局、psqlは '\ 0'バイトに悪影響を及ぼします)が、16進数またはbase64は簡単に取得でき、psqlの外部で後処理できます。
シェルの例、GNU coreutilsからのbase64
コマンドの存在を想定:
$ psql -Atc "select encode(bytea_column,'base64') from tablename" | \
base64 -d >/path/to/destination/filename
これは、一度に1つの行と列だけを出力します。同時に別の列(IDなど)を抽出することは、後処理が大幅に困難になるため、この簡単な例では、以前に取得したIDを通過するある種の外部ループを想定しています。