PostgreSQL フロントエンド/バックエンドプロトコル
PostgreSQLのバイナリ型のデータって、PostgreSQLのフロントエンド/バックエンドプロトコル上では、どういう形式になっているのか、ちょっと調べてみた。
結論からいえば、少なくともlibpqを使った場合には、バイナリ型のデータであっても、テキスト形式としてサーバ/クライアント間では通信されているように思える。
検証
調査のために使ったのはstoneというTCP/UDPリピータ。これにはダンプのオプションがあって、それを使って中を見てみることにする。
とりあえずstoneをこんな感じで起動しておく。
$ stone -ppp localhost:5434 5435
で、psqlで5435ポートのほうに接続して、バイナリ型を含むテーブルにSELECT文をほいっと発行してみる。
$ psql test -h localhost -p 5435 psql (9.1.4) Type "help" for help. test=# \d bin_test Table "public.bin_test" Column | Type | Modifiers --------+---------+----------- id | integer | t_data | text | b_data | bytea | test=# SELECT * FROM bin_test; id | t_data | b_data ----+--------+-------- 1 | abc001 | \x0101 (1 row)
すると、stoneを起動したターミナルにどわーっとダンプが出力される。
とりあえず最初はすっとばして、SELECT文の発行から結果返却までを抜き出すと・・・
Jun 7 11:14:22.421401 47663467702496 3 5>6 51 00 00 00 1c 53 45 4c Q....SEL Jun 7 11:14:22.421427 47663467702496 3 5>6 45 43 54 20 2a 20 46 52 ECT * FR Jun 7 11:14:22.421439 47663467702496 3 5>6 4f 4d 20 62 69 6e 5f 74 OM bin_t Jun 7 11:14:22.421463 47663467702496 3 5>6 65 73 74 3b 00 est;. Jun 7 11:14:22.423138 47663467702496 3 5<6 54 00 00 00 4d 00 03 69 T...M..i Jun 7 11:14:22.423152 47663467702496 3 5<6 64 00 00 00 4a 59 00 01 d...JY.. Jun 7 11:14:22.423162 47663467702496 3 5<6 00 00 00 17 00 04 ff ff ........ Jun 7 11:14:22.423173 47663467702496 3 5<6 ff ff 00 00 74 5f 64 61 ....t_da Jun 7 11:14:22.423183 47663467702496 3 5<6 74 61 00 00 00 4a 59 00 ta...JY. Jun 7 11:14:22.423193 47663467702496 3 5<6 02 00 00 00 19 ff ff ff ........ Jun 7 11:14:22.423211 47663467702496 3 5<6 ff ff ff 00 00 62 5f 64 .....b_d Jun 7 11:14:22.423221 47663467702496 3 5<6 61 74 61 00 00 00 4a 59 ata...JY Jun 7 11:14:22.423231 47663467702496 3 5<6 00 03 00 00 00 11 ff ff ........ Jun 7 11:14:22.423253 47663467702496 3 5<6 ff ff ff ff 00 00 44 00 ......D. Jun 7 11:14:22.423265 47663467702496 3 5<6 00 00 1f 00 03 00 00 00 ........ Jun 7 11:14:22.423274 47663467702496 3 5<6 01 31 00 00 00 06 61 62 .1....ab Jun 7 11:14:22.423284 47663467702496 3 5<6 63 30 30 31 00 00 00 06 c001.... Jun 7 11:14:22.423294 47663467702496 3 5<6 5c 78 30 31 30 31 43 00 \x0101C. Jun 7 11:14:22.423343 47663467702496 3 5<6 00 00 0d 53 45 4c 45 43 ...SELEC Jun 7 11:14:22.423355 47663467702496 3 5<6 54 20 31 00 5a 00 00 00 T 1.Z... Jun 7 11:14:22.423364 47663467702496 3 5<6 05 49 .I
こんなダンプが出てくる。
で、この中をPostgreSQL文書の53.7. メッセージの書式を参考にしながら読んでみる。
Queryメッセージ
最初はQueryメッセージ
51 00 00 00 1c 53 45 4c 45 43 54 20 2a 20 46 52 65 73 74 3b 00
- 先頭が'Q'なので簡易問い合わせ(Query)である。
- 0000001c(28)の長さのメッセージ
- 以降はSQL文そのもの。(SELECT * FROM bin_test)
RowDescriptionメッセージ
次はRowDescriptionメッセージ
65 73 74 3b 00・・・
- 先頭が'T'なのでメッセージ行の記述である(RowDescription)。
- 00 00 00 4d 長さ=77のメッセージであることを示す。
- 00 03 は行のフィールド数=3を示す。
- 69 64 00 は"id"(null-terminate)
- 00 00 4a 59 はテーブルのオブジェクトID(19033)
- オブジェクトIDの確認
test=# select oid, relname from pg_class where relname = 'bin_test'; oid | relname -------+---------- 19033 | bin_test (1 row)
- 00 01 は"id"列の属性番号(1)。
- 00 00 00 17 は"id"列のデータ型のオブジェクトID(23, int4)
- 00 04 はデータ型の大きさ(4)
- ff ff ff ff は型修飾子(-1)。-1は特に設定なしを示す。
- 00 00 フィールドに使用される書式コード(0)。0なのでテキスト書式を示す。
で、以下2つのカラムについての情報が展開される。
- 74 5f 64 61 74 61 00 は列名(t_data)
- 00 00 4a 59 はテーブルのオブジェクトID(19033)
- 00 02 は"t_data"列の属性番号(2)。
- 00 03 はデータ型(text)
- 00 00 00 19 は"t_data"列のデータ型のオブジェクトID(25, text)
- ff ff はデータ型の大きさ(-1, 可変長)
- ff ff ff ff は型修飾子(-1)。-1は特に設定なしを示す。
- 00 00 フィールドに使用される書式コード(0)。0なのでテキストを示す。
- 62 5f 64 61 74 61 00 は列名(b_data)
- 00 00 4a 59 はテーブルのオブジェクトID(19033)
- 00 03 は"b_data"列の属性番号(3)。
- 00 00 00 11 は"b_data"列のデータ型のオブジェクトID(17, bytea)
- ff ff はデータ型の大きさ(-1, 可変長)
- ff ff ff ff は型修飾子(-1)。-1は特に設定なしを示す。
- 00 00 フィールドに使用される書式コード(0)。0なのでテキストを示す。
- ★ つまり、bytea型でもテキスト書式で送信?
DataRow
次はDataRowメッセージ。
44 00 00 1f 00 03 00 00 00 ・・・
- 先頭が'D'なのでデータ行(DataRow)の記述である。
- 00 00 00 1f は自身を含む、メッセージ内容の長さ(31バイト)。
- 00 03 は後に続く列値の数(3)
- 00 00 00 01 は列1のデータ長(1)
- 31 は列1の値"1"
- 00 00 00 06 は列2のデータ長(6)
- 61 62 63 30 30 31 は列2のデータ"abc012"
- 00 00 00 06 は列3のデータ長(6)
- 5c 78 30 31 30 31 は列3のデータ"\x0101C"
- ★バイナリ型を文字列化表現したデータ形式
CommandComplete
その後はCommandCompleteメッセージ
- 先頭が'C'(0x43)なのでCommandCompleteの記述である。
- 00 00 00 0d は自身を含む、メッセージ内容の長さ(13バイト)
- 53 45 4c 45 43 54 20 31 00 はコマンドタグを示す(SELECT 1)。"1"は取り込んだ行数を示す。