HHeLiBeXの日記 正道編

日々の記憶の記録とメモ‥

「トランザクション内でユニークなTIMESTAMP値を取得する試み」内での誤解

だいぶ前に、トランザクション内でユニークなTIMESTAMP値を取得する試み - HHeLiBeXの日記 正道編でGlobal Temporary Tableを使ったアプローチを書いたが、SQL規格上でのGlobal Temporary Tableに関して誤った理解をしていたことが判明。*1


Global Temporary Tableは、あらかじめ

CREATE GLOBAL TEMPORARY TABLE SQL_TBL_UNIQUE_TIMESTAMP (UNIQ_TS TIMESTAMP)
   ON COMMIT DELETE ROWS

と定義しておくと、トランザクションのセッションが開始されたときにそのセッション専用のテーブルインスタンスが生成されるらしい。つまり、Global Temporary Tableの定義自体はオブジェクト指向言語におけるクラス定義をするのと同じということ。


ということで、以前に書いた定義を書き直すと、以下のような感じ。

あらかじめ、

CREATE GLOBAL TEMPORARY TABLE SQL_TBL_UNIQUE_TIMESTAMP (UNIQ_TS TIMESTAMP)
   ON COMMIT DELETE ROWS

CREATE FUNCTION SQL_UNIQUE_TIMESTAMP()
   RETURNS TIMESTAMP
   LANGUAGE SQL
   NOT DETERMINISTIC
   MODIFIES SQL DATA

   BEGIN
      DECLARE Result TIMESTAMP;
      DECLARE Flag_NotFound INTEGER DEFAULT 0;

      DECLARE CONTINUE HANDLER FOR NOT FOUND SET Flag_NotFound = 1;

      SELECT UNIQ_TS INTO Result
         FROM SQL_TBL_UNIQUE_TIMESTAMP;
      IF Flag_NotFound = 1 THEN
         SET Result = CURRENT_TIMESTAMP;
         INSERT INTO SQL_TBL_UNIQUE_TIMESTAMP ( UNIQ_TS )
            VALUES ( Result );
      END IF;

      RETURN Result;
   END

を定義しておく。

以前と変わったのは、Global Temporary Table参照時に動的SQLを使用していないことと、初期化を関数の中でまとめてやってしまっている点。もちろん、セッション開始後にできるだけ早く初期化を行うことでトランザクション開始時刻にできるだけ近いタイムスタンプ値を使いたいということであれば、Global Temporary Tableの初期化だけは先にやるというのもあり。

で、

INSERT INTO TBL(ID, TS) VALUES(1, SQL_UNIQUE_TIMESTAMP())

INSERT INTO TBL(ID, TS) VALUES(2, SQL_UNIQUE_TIMESTAMP())

のように定義した関数を呼び出せば、セッション中でユニークなTIMESTAMP値が取得できる。

*1:なぜ誤解していたかというと、DB2では"DECLARE GLOBAL TEMPORARY TABLE"としてセッションごとに「宣言」する必要があったから。