Interval型に関して煩悶すること
ひょんなことで、PostgreSQLのinterval型についてちょっくら調べてみることになったんだけど、そこでPostgreSQL文書の記述が正しいのかどうか悩むことが一点あった。
http://www.postgresql.jp/document/9.3/html/datatype-datetime.htmlでは、interval型の格納領域は12バイトとかかれているのだが、35.9.2. C言語関数における基本型を参考に、interval型のC言語型(datatype/timestamp.h)を調べてみると、16バイトあるようにしか思えないのだが・・・
#ifdef HAVE_INT64_TIMESTAMP typedef int64 Timestamp; typedef int64 TimestampTz; typedef int64 TimeOffset; typedef int32 fsec_t; /* fractional seconds (in microseconds) */ #else typedef double Timestamp; typedef double TimestampTz; typedef double TimeOffset; typedef double fsec_t; /* fractional seconds (in seconds) */ #endif typedef struct { TimeOffset time; /* all time units other than days, months and * years */ int32 day; /* days, after time for alignment */ int32 month; /* months and years, after time for alignment */ } Interval;
TimeOffsetがint64側で定義されていようが、doubleで定義されていようが、やっぱり16バイトじゃないのか?
ってことで、実際にinterval型のカラムをもつテーブルを作ってデータを放り込んでみた。
sample=# CREATE TABLE datetime_test (d date, ts timestamp, iv interval); CREATE TABLE sample=# INSERT INTO datetime_test VALUES ('2014-01-01', '2014-01-01 00:00:00', '1 year 2 months 3 days 4 hours 5 minutes 6 seconds'); INSERT 0 1 sample=# CHECKPOINT; CHECKPOINT sample=#
で、これでdatetime_testテーブルのテーブルファイルをhexdumpでダンプしてみる。
[nuko]$ hexdump -C 57558 00000000 00 00 00 00 90 02 32 99 00 00 00 00 1c 00 c8 1f |......2.........| 00000010 00 20 04 20 00 00 00 00 c8 9f 70 00 00 00 00 00 |. . ......p.....| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 00001fc0 00 00 00 00 00 00 00 00 c7 7c 0f 00 00 00 00 00 |.........|......| 00001fd0 00 00 00 00 00 00 00 00 01 00 03 00 00 08 18 00 |................| 00001fe0 fa 13 00 00 00 00 00 00 00 c0 73 20 dc 91 01 00 |..........s ....| 00001ff0 80 c0 8b 6c 03 00 00 00 03 00 00 00 0e 00 00 00 |...l............| 00002000 [nuko]$
0x00001ff0 からinteval型の領域だ。ちなみに手元の環境だとTimeOffsetはint64型管理っぽい。
- 最初の8バイトがTimeOffset型のtime
- 0x000000036c8bc080 => 14706000000(マイクロ秒) => 4時間5分6秒
- 次の4バイトがint32型のday
- 0x00000003 => 3日
- 次の4バイトがint32型のmonth
- 0x0000000e => 14ヶ月 => 1年2ヶ月
やっぱり、ダンプ結果を見てもinterval型の領域は16バイトのようにしか思えぬ・・・
でも、PostgreSQL文書の遥か昔から(7.2まで一応見てみた)、ずっとここは12バイトのまま(かつ最遠の過去、最遠の未来の値域も変わらず)なんだよなあ。いくらなんでも、単なる誤植ならとうの昔に修正されていると思う。何か、俺が理解しきれていない理由によって、intervalの格納領域は12バイトということなのだろうか・・・わからぬ。
ということで数十分ほど煩悶している。