PostgreSQL の PITR で指定できるタイムスタンプの形式
Posted on
PostgreSQL の Point In Time Recovery (PITR) は任意の時点までデータベースをリカバリできる機能です。 recovery.conf に recovery_target_time を指定することでリカバリする時間を決めますが、ドキュメントを読んでも指定できる値が timestamp としか書いてなく非常にわかりにくいです。
「PostgrSQL 全機能バイブル」で調べてみると、こんな感じで指定できることがわかりました(この本はおすすめです)。
recovery_target_time = '2014-03-11 15:00:00 JST'
ググってみると、タイムゾーンを JST ではなく +09 と指定する方法もあるようです。 recovery_target_time に指定できる正しい形式が気になってきました。
ソースコードを読んでみる
ドキュメントがアテにならないのならソースコードを読むしかありません。 3/11 時点の最新版である PostgrSQL 9.3.3 のソースコードを読んでみます。
recovery_target_time で grep すると、postgresql-9.3.3/src/backend/access/transam/xlog.c:4271 にそれらしいコードが見つかります。
/*
* Convert the time string given by the user to TimestampTz form.
*/
recoveryTargetTime =
DatumGetTimestampTz(DirectFunctionCall3(timestamptz_in,
CStringGetDatum(item->value),
ObjectIdGetDatum(InvalidOid),
Int32GetDatum(-1)));
今度は呼び出されている timestamptz_in で grep すると、postgresql-9.3.3/src/backend/utils/adt/timestamp.c:409 に定義されていました。
/* timestamptz_in()
* Convert a string to internal form.
*/
Datum
timestamptz_in(PG_FUNCTION_ARGS)
{
...
処理は 433 行目から行われています。
dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
field, ftype, MAXDATEFIELDS, &nf);
if (dterr == 0)
dterr = DecodeDateTime(field, ftype, nf, &dtype, tm, &fsec, &tz);
if (dterr != 0)
DateTimeParseError(dterr, str, "timestamp with time zone");
実際の変換処理をしているであろう DecodeDateTime でさらに grep すると、postgresql-9.3.3/src/backend/utils/adt/datetime.c:763 のコメントに答えがありました。
/* DecodeDateTime()
* Interpret previously parsed fields for general date and time.
* Return 0 if full date, 1 if only time, and negative DTERR code if problems.
* (Currently, all callers treat 1 as an error return too.)
*
* External format(s):
* "<weekday> <month>-<day>-<year> <hour>:<minute>:<second>"
* "Fri Feb-7-1997 15:23:27"
* "Feb-7-1997 15:23:27"
* "2-7-1997 15:23:27"
* "1997-2-7 15:23:27"
* "1997.038 15:23:27" (day of year 1-366)
* Also supports input in compact time:
* "970207 152327"
* "97038 152327"
* "20011225T040506.789-07"
*
* Use the system-provided functions to get the current time zone
* if not specified in the input string.
*
* If the date is outside the range of pg_time_t (in practice that could only
* happen if pg_time_t is just 32 bits), then assume UTC time zone - thomas
* 1997-05-27
*/
"Interpret previously parsed fields for general date and time." とあるので一般的な日付と時刻の形式は使えるようです。さらに、"20011225T040506.789-07" のようなミリ秒を指定した形式も受け付けるみたいです。
まとめ
ドキュメントに書いてなければソースコードを読む!(でも、ソースコードにだけ例を載せるのはやめてほしい…)