web-dev-qa-db-ja.com

テーブルのすべてのバイナリ列をファイルとしてダンプする

bytea型の列を持つpostgresqlデータベースにテーブルがあります。ファイル名としてidを使用して、各バイナリエントリをファイルとしてドロップしたいと思います。

この場合、SQLクエリはどのようになりますか?

4
tzippy

Byteaをディスクサーバー側に保存するには、データベースのスーパーユーザーである必要があります。通常のユーザーはファイルシステムへの書き込みを許可されていません。

スーパーユーザー権限を想定すると、最も簡単な方法は、「信頼されていない」言語の1つで関数として実装することです。

Pl/perluの例:

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に作成される可能性があります。ファイルとしてエクスポートする前に一時的なラージオブジェクトを作成し、データ全体をコピーしてから、ラージオブジェクトを削除する必要があるため、非効率的です。

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インタープリターである場合、バイナリコンテンツを直接抽出することはできません(結局、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を通過するある種の外部ループを想定しています。

5
Daniel Vérité