日付関数に関する検証 外伝 その1

投稿日:

<日付関数に関する検証 外伝>
ペンネーム: ダーリン

【SYSTIMESTAMPとCURRENT_TIMESTAMPの怪 その1】

大変ご無沙汰しております。久々登場のダーリンです。
今回は日付関数のちょっと変わった動きについてお話させていただきます。

Oracle 9i 以降、秒未満の時刻を表示できる日付時刻に関する関数が増えてい
ることはすでにご存知かと思います。
従来から存在する SYSDATE 関数とあわせるとこれらは以下の 5つの関数です。

     SYSDATE                DATE型
     SYSTIMESTAMP           TIMESTAMP WITH TIMEZONE型
     CURRENT_DATE           DATE型
     CURRENT_TIMESTAMP      TIMESTAMP WITH TIMEZONE型
     LOCAL_TIMESTAMP        TIMESTAMP型

すでに気がついている方もいるかと思いますが、 実は上記の関数のなかであ
る組み合わせの関数を実行すると、、、ちがう値を取得してきます。
タイムゾーンの設定による違いではありません。
タイムゾーンについてはこちら
(http://www.atmarkit.co.jp/fdb/rensai/sqlclinic04/sqlclinic04_3.html)を
参照してみてください。

ここでいう異なる値とは、ミリ秒(1/1000秒)以下のずれのことです。

以下はその実例です。

SQL> select SYSDATE,SYSTIMESTAMP,CURRENT_TIMESTAMP,LOCALTIMETAMP from dual;

SYSDATE  SYSTIMESTAMP                    CURRENT_TIMESTAMP               
-------- ------------------------------- ------------------------------- 
06-11-20 06-11-20 21:40:40.978854 +09:00 06-11-20 21:40:40.978898 +09:00 

LOCALTIMESTAMP
------------------------
06-11-20 21:40:40.978898

SYSTIMESTAMP と、 CURRENT_TIMESTAMP および LOCALTIMESTAMP の時刻が数十
マイクロ秒のレベルでずれていますね。

多くの方は上記の SQL では暗黙的に同じ値が取得されることを期待している
のではないでしょうか?

日付関数を並べるなんてナンセンスと思われるかもしれませんが、これらの日
付関数では取得される TIMEZONE が異なるため、TIMEZONE を意識する場合は
便利な使い方です。

これらの関数について、マニュアルにはおおよそ以下のように記載されていま
す。

SYSDATE            このファンクションはローカル・データベースの
                   日時を戻します。
SYSTIMESTAMP       データベースが存在するシステムの タイムゾーン
                   (小数部を含む)を戻します。
CURRENT_DATE       セッション・タイムゾーンの現在の日付を DATE 
                   データ型のグレゴリオ暦の値で戻します。
CURRENT_TIMESTAMP  セッション・タイムゾーンの現在の日付および
                   時刻をTIMESTAMP WITH TIME ZONE データ型の値
                   で戻します。
LOCALTIMESTAMP     セッションのタイムゾーンの現在の日付および
                   時刻をTIMESTAMPデータ型の値で戻します。

つまり SYSDATE 関数と SYSTIMESTAMP 関数はローカルデータベース、あるい
は、システムの日時データを戻しているのに対し、それ以外の関数はセッショ
ンタイムゾーンを考慮した日時を戻しているようです。
日時データのデータソースが異なるか、あるいは、同一データに対して変換を
かけて値を取得しているのでしょうか。

Oracle がそもそもどうやって日付時刻の情報を取得しているのか気になります。

こんなときどうすればこのような情報を得ることができるでしょうか?
何か尻尾ぐらいはつかめないでしょうか。 というわけで、今回はトレースを
とることにします。

まず、psコマンドでトレースを取得するプロセスを見つけます。
トレースする対象のセッションは専用接続で接続し、 そのプロセスを特定する
ほうがわかりやすくておすすめです。

今回はLinux上でトレースを取得するので、strace コマンドを使ってみます。

□■ 対象セッションのプロセス特定
$ ps -elf | grep oracle | grep test1 | grep beq
000 S oracle   15690     1  1  77   0    - 60699 pipe_w 21:40 ?   00:00:00 oracletest1 (DESCRIPTION=(LOCAL=YES)(ADDRESS=(PROTOCOL=beq)))


□■ 対象セッションのトレース
$ strace -p 15690
Process 15690 attached - interrupt to quit
read(8,

strace コマンドの 第2引数はトレースするPIDです。
これで準備完了です。では対象のセッションで日付を取得してみましょう。

まずはSYSDATEです。

SQL> select SYSDATE from dual;

SYSDATE
--------