Yet another OSS DB:Firebird(終)

ユーザー定義関数で日付時刻やBLOBを扱う

Firebird日本ユーザー会
アナハイムテクノロジー
はやしつとむ
2009/7/21
内部関数が足りなければ、UDFを作ってしまおうということで、前回はFirebirdのUDF(ユーザー定義関数)の作成方法やその使用方法を取り上げました。今回は日付時刻型の取り扱いや、BLOB型の取り扱いについて見ていきたいと思います。

Firebirdでの日付時刻型の扱い

 Firebirdの内部における日付時刻型は、そのままではCやDelphiで利用することができません。そのため、以下のAPIを利用してFirebirdから渡された日付時刻を変換し、また、戻り値として渡さなくてはなりません。

●isc_decode_sql_date():
 Firebirdの内部日付形式をCの日付構造体に変換する

●isc_encode_sql_date():
  Cの日付構造体をFirebirdの内部日付形式に変換する

●isc_decode_sql_time():
  Firebird内部時刻形式をCの時刻構造体に変換する

●isc_encode_sql_time():
  Cの時刻構造体をFirebirdの内部時刻形式に変換する

●isc_decode_timestamp():
  Firebirdの内部タイムスタンプ形式をCのタイムスタンプ構造体に変換する(従来はisc_decode_date()でした。これは、下位互換性のために残されています)

●isc_encode_timestamp():
  Cのタイムスタンプ構造体をFirebirdの内部タイムスタンプ形式に変換する(従来はisc_encode_date()でした。これは、下位互換性のために残されています)

 ib_udfライブラリには日付時刻型の関数は含まれていないので、fbudfライブラリのコードを見てみることにしましょう。

fbudf.cpp(517)
FBUDF_API ISC_TIMESTAMP* addYear(ISC_TIMESTAMP* v, const ISC_LONG& nyears)
{
tm times;
internal::decode_timestamp(v, &times);
times.tm_year += nyears;
internal::encode_timestamp(&times, v);
return v;
}

 まず、Cの時刻型であるtm型のtimesを宣言し、ISC_TIMESTAMP型で渡されてきたvをisc_decode_timestamp()関数でCの時刻型に変換しています。そして、tm型のメンバであるtm_yearにint型で渡されたnyearを加算しています。そのtimesをisc_encode_timestamp()関数を使って再びFirebirdのTimestamp型へ変換して戻しています。

 では、Delphiで同じことをしてみます。

library UDF_sample2;

uses
  SysUtils, Windows;

type

 TM = record
    tm_sec : integer;   // Seconds
    tm_min : integer;   // Minutes
    tm_hour : integer;  // Hour (0--23)
    tm_mday : integer;  // Day of month (1--31)
    tm_mon : integer;   // Month (0--11)
    tm_year : integer;  // Year (calendar year minus 1900)
    tm_wday : integer;  // Weekday (0--6) Sunday = 0)
    tm_yday : integer;  // Day of year (0--365)
    tm_isdst : integer; // 0 if daylight savings time is not in effect)
  end;

  PTM   = ^TM;

  Long = Longint;
  ULong= Longword;

  ISC_TIMESTAMP = record
    timestamp_date : Long;
    timestamp_time : ULong;
  end;

  PISC_TIMESTAMP = ^ISC_TIMESTAMP;

procedure isc_encode_timestamp  
 (tm_date: PTM; ib_date: PISC_TIMESTAMP);stdcall; external 'fbclient.dll';

procedure isc_decode_timestamp  
 (ib_date: PISC_TIMESTAMP;tm_date: PTM); stdcall; external 'fbclient.dll';

procedure isc_decode_sql_date   
 (var ib_date: Long;tm_date: PTM); stdcall; external 'fbclient.dll';

procedure isc_encode_sql_date   
 (tm_date: PTM; var ib_date: Long); stdcall; external 'fbclient.dll';

procedure isc_decode_sql_time   
 (var ib_date: ULong;tm_date: PTM); stdcall; external 'fbclient.dll';

procedure isc_encode_sql_time   
 (tm_date: PTM; var ib_date: ULong); stdcall; external 'fbclient.dll';

{$R *.res}

function tomneko_addYear(var v:ISC_TIMESTAMP; var nyears:Integer):PISC_TIMESTAMP;stdcall;
var
  times:tm;
begin
	isc_decode_timestamp(@v, @times);
	times.tm_year := times.tm_year + nyears;
	isc_encode_timestamp(@times, @v);
	result := @v;
end;

exports
  tomneko_addYear;

begin
end.

●登録用スクリプト:

DECLARE EXTERNAL FUNCTION TOMNEKO_ADDYEAR
TIMESTAMP, INTEGER 
RETURNS TIMESTAMP 
ENTRY_POINT 'tomneko_addYear' 
MODULE_NAME 'UDF_sample2';

●使用例:

SQL> CREATE TABLE T_DATE (TM DATE);
SQL> INSERT INTO T_DATE VALUES ('2004/1/1');
SQL> SELECT TOMNEKO_ADDYEAR(TM, 2) FROM T_DATE;
          TOMNEKO_ADDYEAR
=========================
2006-01-01 00:00:00.0000

 Firebirdから渡されたvのアドレスを、そのままresultとしているところがミソで、戻り値用にtm型のメモリを確保しないようにしているわけです。


1/4 次のページへ

Index
ユーザー定義関数で日付時刻やBLOBを扱う
→ Page 1
Firebirdでの日付時刻型の扱い

Page 2
EncodeDate関数
UDFでBLOBを扱う

Page 3
BLOB UDFのサンプル(1)
BLOB UDFのサンプル(2)

Page 4
最後に

Yet another OSS DB:Firebird


Database Expert フォーラム 新着記事
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Database Expert 記事ランキング

本日月間