2014年6月12日木曜日

(32bit限定)SQL-Server 2000でも、関数の中でシステム日付を取得する方法

まだまだ現役かと思う、マイクロソフトの古いRDBMSの「SQL-Server 2000」ですが、何と、関数の中でシステム日付を求める事が出来ません。

GETDATE()のような、実行のたびに結果が変化する関数は使えないという謎の仕様になっています。

システム日付を使いたい場合は、関数の外側で求めて、それをパラメータとして関数に引き渡して中で使う・・・というやり方がセオリーなんですが、既存の関数のインターフェースを絶対に変えたくないし、仕様変更等で内部でシステム日付使いたい・・・みたいな時には、結構困るかも。

そこで、ちょっと無理やりなのですが、32bit限定で、関数の中で使える、システム日付を求める関数を作ってみました。

この関数を、自分で作った関数の中から呼び出せばOKです。

やり方は、OLEオートメーションプロシージャを使って、スクリプトエンジンを呼び出し、JScriptで記述したシステム日付取得関数を間接的に呼び出してしまう・・・というものなんです。

32bit限定というのは、呼び出しているスクリプトエンジンが64bit対応してないんですね。

ちなみに、手のひらタブレットの東芝dynabook tab VT484で作りました。

SQL-Server 2014 EXPRESS(32bit版)なんですが、SQL-Server 2000でも使えます。

コードは以下のようになります。


CREATE FUNCTION F_GETDATE()
RETURNS DATETIME
AS
BEGIN
   DECLARE 
   @oOLEAP INT, --OLEオートメーションインスタンス化用
   @iHR    INT, --OLEオートメーションプロシージャ実行結果
   @sRES   VARCHAR(8000), --文字列型の結果格納エリア
   @dtRES  DATETIME,      --日付型結果格納エリア
   @sJS    VARCHAR(8000)  --JScript格納エリア
   ;
   
   --スクリプトエンジンのインスタンス化
   EXEC @iHR= 
   sp_OACreate 'MSScriptControl.ScriptControl',@oOLEAP OUT;

   IF @iHR <> 0
   BEGIN
      RETURN CAST(0 AS DATETIME);
   END;
   
   --言語の決定
   EXEC @iHR=
   sp_OASetProperty @oOLEAP,'Language','JScript';
   IF @iHR <> 0
   BEGIN
      RETURN CAST(0 AS DATETIME);
   END;
   
   --初期化
   EXEC @iHR=
   sp_OAMethod @oOLEAP,'Reset'
   IF @iHR<>0
   BEGIN
      RETURN CAST(0 AS DATETIME);
   END;
   
   --JScriptで日付取得関数作成
   SET @sJS =
   'function JS_GETDATE()' +
   '{'                     +
   'var oDATE = new Date();' +
   'var sDATE = "";'         +
   'sDATE += new String(oDATE.getFullYear()) + "-"; ' +
   'sDATE += new String(oDATE.getMonth()+1)  + "-"; ' +
   'sDATE += new String(oDATE.getDate())     + " "; ' +
   'sDATE += new String(oDATE.getHours())    + ":"; ' +
   'sDATE += new String(oDATE.getMinutes())  + ":"; ' +
   'sDATE += new String(oDATE.getSeconds())  + "."; ' +
   'sDATE += new String(oDATE.getMilliseconds());   ' +
   'oDATE = null;                                   ' +
   'return sDATE;                                   ' +
   '}';
   
   --JScriptで作った関数をメソッド登録
   EXEC @iHR=
   sp_OAMethod @oOLEAP,'AddCode',NULL,@sJS;
   if @iHR<>0
   BEGIN
      RETURN CAST(0 AS DATETIME);
   END;
   
   --JScript関数を実行して戻り値を文字列で取得
   EXEC @iHR=
   sp_OAMethod @oOLEAP,'Run',@sRES OUT,'JS_GETDATE';
   IF @iHR<>0
   BEGIN
      RETURN CAST(0 AS DATETIME);
   END;
   
   --日付型に変換
   SET @dtRES = CAST(@sRES AS DATETIME);
   
   --メモリ解放
   EXEC @iHR=
   sp_OADestroy @oOLEAP;
   if @iHR<>0
   BEGIN
      RETURN CAST(0 AS DATETIME);
   END;
   
   --結果の返却
   RETURN @dtRES;
END


ちなみに、OLEオートメーションプロシージャは、最初は使えなくなっているかも知れません。 その場合は以下で使用可能になります。

sp_configure 'show advanced options', 1;
GO
RECONFIGURE;
GO
sp_configure 'Ole Automation Procedures', 1;
GO
RECONFIGURE;
GO

実行結果は以下の通りです。
GETDATE()と同じように動作し、自作関数からも動作します。




ただ、OLEオートメーションプロシージャって、どうなんだろう。

作っておいて今更ですが、業務システムとかで安易に使うと、リソースデッドロックとか、パフォーマンスの低下とか、色々問題が起きるかも知れないんで怖いかなぁと。

個人用途とかなら良いかも知れない。

ただ、OLEオートメーションプロシージャを使うと、確かに色々な事が出来るようになるので便利ではありますね。