Yet another OSS DB:Firebird(終)

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

Firebird日本ユーザー会
アナハイムテクノロジー
はやしつとむ
2009/7/21

EncodeDate関数

 Firebirdで日付時刻型を扱う場合に、組み込まれている関数で大抵のことはできるようになっています。例えばOracleのTO_DATE()関数の置き換えは、CAST()関数を使って日付時刻型の文字列から日付時刻型への変換を行うことができるので問題ありませんし、逆に日付時刻型から年・月・日を取り出すためにはEXTRACT()関数を使って、EXTRACT(YEAR FROM T.TM)とすれば年を取り出すことができます。そこで、EXTRACT()の逆変換にあたる、DelphiでいうところのEncodeDate()関数をUDFにしてみたいと思います。これは、年・月・日を整数で与えると、TIMESTAMP型で返すというものです。

 APIコールの定義をそのまま利用したいので、先ほどのUDF_sample2に追加することとしました。戻り値をPARAMETERで返すように作成するので、functionではなくてprocedureで作成します。

 戻り値になるv:ISC_TIMESTAMPが引数の最後にくるようにしておきます。exports節へ関数名を追加するのを忘れると、呼び出せないので注意してください。

procedure tomneko_EncodeDate(var year, month, day:Integer; var v:ISC_TIMESTAMP);stdcall;
var
  times:tm;
begin
  times.tm_year := year  - 1900;
  times.tm_mon  := month - 1;
  times.tm_mday := day;
  times.tm_hour := 0;
  times.tm_min  := 0;
  times.tm_sec  := 0;
  times.tm_isdst:= 0;
  isc_encode_timestamp(@times, @v);
end;

●登録用スクリプト:

DECLARE EXTERNAL FUNCTION TOMNEKO_ENCODEDATE
INTEGER, INTEGER, INTEGER, TIMESTAMP
RETURNS PARAMETER 4
ENTRY_POINT 'tomneko_EncodeDate' 
MODULE_NAME 'UDF_sample2';

●使用例:

SQL> SELECT TOMNEKO_ENCODEDATE(2009,1,1)
CON> FROM RDB$DATABASE;

       TOMNEKO_ENCODEDATE
=========================
2009-01-01 00:00:00.0000

UDFでBLOBを扱う

 UDFでBLOBを扱う場合、いくつかの注意が必要です。BLOBがUDFに渡される、あるいは返される場合、それは以下に示すBLOB制御構造体へのポインタとなります。BLOBの実データに対しては、このBLOB制御構造体を通してアクセスすることになります。

●BLOB制御構造体:C言語の定義:

jrd\fun.e(91)
   static SSHORT blob_get_segment(blb*, UCHAR*, USHORT, USHORT*);
   static void blob_put_segment(blb*, const UCHAR*, USHORT);
jrd\fun.epp(172)
   struct udf_blob
   {
   SSHORT (*blob_get_segment) (blb*, UCHAR*, USHORT, USHORT*);
   void* blob_handle;
   SLONG blob_number_segments;
   SLONG blob_max_segment;
   SLONG blob_total_length;
   void (*blob_put_segment) (blb*, const UCHAR*, USHORT);
   SLONG (*blob_seek) (blb*, USHORT, SLONG);
   };

●BLOB制御構造体:Delphiの定義:

IBExternal.pas(38)
type
  Long         = LongInt; { 32 bit signed }
  Short        = SmallInt;{ 16 bit signed }
PInt         = ^Int;


TISC_BlobGetSegment = 
  function(BlobHandle: PInt;
             Buffer: PChar;
             BufferSize: Long;
             var ResultLength: Long): Short; cdecl;
TISC_BlobPutSegment = 
  procedure(BlobHandle: PInt;
              Buffer: PChar;
              BufferLength: Short); cdecl;
  TBlob = record
    GetSegment         : TISC_BlobGetSegment;
    BlobHandle         : PInt;
    SegmentCount       : Long;
    MaxSegmentLength   : Long;
    TotalSize          : Long;
    PutSegment         : TISC_BlobPutSegment;
  end;
PBlob = ^TBlob;
【注】
Delphiでの定義は、IPLに基づいて公開されているIBXのソースコードから、必要な部分のみ引用しています。最新版のDelphiに付属するものは、Bufferの型がPByteになるなど、若干の変更があります。これは、Delphi2009でUnicode対応のためにPCharがPWideCharへのエイリアスとなってしまったため、これまでC同様にやってきたCharはByteという常識が通用しなくなってしまったためです。

 BLOB構造体の各フィールドはそれぞれ以下のような機能を持っています。

●blob_get_segment:
  BLOB制御構造体の最初のフィールドであるblob_get_segmentは、読み取り用の関数へのポインタとなっています。UDFからBLOBを読み取る場合は、この関数を呼び出して、BLOBからセグメントを読み取ります。

 blob_get_segmentの引数は4つあり、BLOBハンドル、読み取りバッファを示すChar型のポインタ(このバッファにBLOBのセグメントが格納されます)、読み取りバッファのサイズ、実際に読み取ったバイト数を格納する変数のアドレスとなります。UDFによるBLOBデータの読み取りが行われない場合、blob_get_segmentをNULLに設定します。

●blob_handle:
  BLOB制御構造体の2番目のフィールドは必須項目です。blob_handleは、UDFに渡されるBLOBの特定に使用され、また、UDFから返されるBLOBの特定に使用されます。isc_blob_handle型は、汎用ポインタです。

●number_segments:
  UDFに渡されたBLOBデータのセグメントの総数が number_segmentsに格納されています。UDFによるBLOBデータの読み取りが行われなかったときには、number_segmentsをNULLに設定します。

●max_seglen:
  UDFに渡されたBLOBデータのセグメントの最大長がバイト数でmax_seglenに格納されています。UDFによるBLOBデータの読み取りが行われなかった場合、max_seglenをNULLに設定します。

●total_size:
  UDFに渡されたBLOBデータの全体のサイズがバイト数でtotal_sizeに格納されています。UDFによるBLOBデータの読み取りが行われなかった場合,max_seglenをNULLに設定します。

●blob_put_segment:
  BLOB制御構造体の最後の項目であるblob_put_segmentは、書き込み用の関数へのポインタとなっています。UDFからBLOBを返す場合には、この関数を使用してBLOBにセグメントを書き込みます。

 blob_put_segmentの引数は3つあり、BLOBハンドル、書込バッファを示すChar型のポインタ(このバッファがBLOBのセグメントに書き込まれます)、書き込まれるデータのサイズ(バイト数)となっています。

前のページへ 2/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 記事ランキング

本日月間