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バイトということなのだろうか・・・わからぬ。

ということで数十分ほど煩悶している。