初出時は「encode関数+バイナリフォーマットでCOPY」しましたが、その後、もっと簡単に普通のCOPYだけで済むと分かり修正・追記しました。(14日)

昨年最後の記事で、「バイナリフォーマットでCOPY」と「Windowsに移植されたddコマンド」をつなげる例を書きました。その後、ddでなくxxdという別のコマンドを使う方法も知り、同じ環境(Windows 7 64bit + PostgreSQL 9.5 RC1)で出来たので補足します。クエリは ↓ こんな感じ。赤が変更点、画像二つ目が出力されたPNGです。
copy (
    select st_asPNG(
        st_asRaster(
            st_buffer(
                st_point(1, 5), 10
            ), 150, 150, '8BUI'
        )
    )
) to program
'"D:/AppsPortable/GitPortable/2.6.2/App/Git/usr/bin/xxd" -r -p > "R:/bytea_to_xxd.png"'
(format binary) -- バイナリフォーマットは不要;


参考リンク、実行環境


実行環境は
ddコマンドの時と同じくWindows 7 64bit + PostgreSQL 9.5 RC1。あとbyteaデータのサンプル作成用にPostGISを使ってますが、byteaデータがあれば何でもいいです。


xxdコマンドは、ddと同様Git Portable 2.6.2に入ってた

ddコマンドを使う際、Windowsに移植されたものとしてGit Portable 2.6.2の中に見つけました。同じ場所にxxdもあったので ↓ 別途探す手間はなし。


とりあえずコマンドラインヘルプを表示すると ↓ 参考リンクで使われている-pというオプションがない…。
LinuxCommand.orgのリファレンスを見て、-p, -ps, -postscript, -plainいずれも同じと分かりました。冒頭のクエリでは-pを使ってます。
$ xxd --help
Usage:
       xxd [options] [infile [outfile]]
    or
       xxd -r [-s [-]offset] [-c cols] [-ps] [infile [outfile]]
Options:
    -a          toggle autoskip: A single '*' replaces nul-lines. Default off.
    -b          binary digit dump (incompatible with -ps,-i,-r). Default hex.
    -c cols     format  octets per line. Default 16 (-i: 12, -ps: 30).
    -E          show characters in EBCDIC. Default ASCII.
    -e          little-endian dump (incompatible with -ps,-i,-r).
    -g          number of octets per group in normal output. Default 2 (-e: 4).
    -h          print this summary.
    -i          output in C include file style.
    -l len      stop after  octets.
    -o off      add  to the displayed file position.
    -ps         output in postscript plain hexdump style.
    -r          reverse operation: convert (or patch) hexdump into binary.
    -r -s off   revert with  added to file positions found in hexdump.
    -s [+][-]seek  start at  bytes abs. (or +: rel.) infile offset.
    -u          use upper case hex letters.
    -v          show version: "xxd V1.10 27oct98 by Juergen Weigert".


COPY ... TO PROGRAMで渡すコマンド内で、リダイレクトが使えた

ddコマンドの時は「of=出力ファイル」で出力先を指定しました。一方xxdは「xxdオプション 入力ファイル 出力ファイル」という文法。最初はこの形式でいろいろ試しましたが上手くいかず(コマンド実行はできるが出力内容が元のバイナリでない)、冒頭のクエリのとおりリダイレクト出力したら成功。PostgreSQLCOPY ... TO PROGRAMでリダイレクトもできると、初めて知りました。


bytea出力時にhex形式でエンコード ← 無駄にバイナリでCOPYしてたのが原因^^;

この項は初出時のままで、その後無意味と分かった情報です。冒頭のクエリだけ見て下さいm(_)m(14日)

参考リンクでは、byteaデータをそのまま出力、またはencode関数でhex形式に変換、の両方がありました。前者の場合、PostgreSQLの環境設定によってhexまたはエスケープ形式のどちらかになり、hexに設定されてればencode関数は使わなくて済みそうな気がします。

ところが今回、出力設定がhexになっている状態でencodeなしでやってみたら ↓ 上手くいかず。環境設定と関係なく常にencode関数でhexにする必要がありました。PostGISPNG出力関数の挙動によるのかも。下の画像二つ目が、出力されたファイルをバイナリエディタStirlingで開いたところ。1バイトしかありません。
select current_setting('bytea_output');
-- 出力形式はhexになってたけど

copy (
    select st_asPNG(
        st_asRaster(
            st_buffer(
                st_point(1, 5), 10
            ), 150, 150, '8BUI'
        )
    )
) to program
'"D:/AppsPortable/GitPortable/2.6.2/App/Git/usr/bin/xxd" -r -p > "R:/test.png"'
(format binary);
-- エンコードなしで出力すると上手くいかない


まとめ