初出時は「encode関数+バイナリフォーマットでCOPY」しましたが、その後、もっと簡単に普通のCOPYだけで済むと分かり修正・追記しました。(1月4日)
昨年最後の記事で、「バイナリフォーマットで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 オプション 入力ファイル 出力ファイル」という文法。最初はこの形式でいろいろ試しましたが上手くいかず(コマンド実行はできるが出力内容が元のバイナリでない)、冒頭のクエリのとおりリダイレクト出力したら成功。PostgreSQLのCOPY ... TO PROGRAMでリダイレクトもできると、初めて知りました。
bytea出力時にhex形式でエンコード ← 無駄にバイナリでCOPYしてたのが原因 ^^;
この項は初出時のままで、その後無意味と分かった情報です。冒頭のクエリだけ見て下さい m(_)m(1月4日)
参考リンクでは、byteaデータをそのまま出力、またはencode関数でhex形式に変換、の両方がありました。前者の場合、PostgreSQLの環境設定によってhexまたはエスケープ形式のどちらかになり、hexに設定されてればencode関数は使わなくて済みそうな気がします。
ところが今回、出力設定がhexになっている状態でencodeなしでやってみたら ↓ 上手くいかず。環境設定と関係なく常にencode関数でhexにする必要がありました。PostGISのPNG出力関数の挙動によるのかも。下の画像二つ目が、出力されたファイルをバイナリエディタ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);
-- エンコードなしで出力すると上手くいかない
まとめ
- ddコマンドの時は「ヘッダのサイズが変わったらどうするか」未解決だったけど、こちらはスッキリ。バイナリフォーマットでCOPYする必要もないし、これ一択でいいと思います。
- でもencode関数でhex形式にする手間があり。使う関数や環境にもよると思うけど。
- 年明け初の記事が「補足」かつ大幅に訂正というのは冴えないなぁ(-_-;) もっと調べてから書けばよかった。