ユーザー定義関数で日付時刻やBLOBを扱う
アナハイムテクノロジー
はやしつとむ
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 |
- Oracleライセンス「SE2」検証 CPUスレッド数制限はどんな仕組みで制御されるのか (2017/7/26)
データベース管理システムの運用でトラブルが発生したらどうするか。DBサポートスペシャリストが現場目線の解決Tipsをお届けします。今回は、Oracle SE2の「CPUスレッド数制限」がどんな仕組みで行われるのかを検証します - ドメイン参加後、SQL Serverが起動しなくなった (2017/7/24)
本連載では、「SQL Server」で発生するトラブルを「どんな方法で」「どのように」解決していくか、正しい対処のためのノウハウを紹介します。今回は、「ドメイン参加後にSQL Serverが起動しなくなった場合の対処方法」を解説します - さらに高度なSQL実行計画の取得」のために理解しておくべきこと (2017/7/21)
日本オラクルのデータベーススペシャリストが「DBAがすぐ実践できる即効テクニック」を紹介する本連載。今回は「より高度なSQL実行計画を取得するために、理解しておいてほしいこと」を解説します - データベースセキュリティが「各種ガイドライン」に記載され始めている事実 (2017/7/20)
本連載では、「データベースセキュリティに必要な対策」を学び、DBMSでの「具体的な実装方法」や「Tips」などを紹介していきます。今回は、「各種ガイドラインが示すコンプライアンス要件に、データベースのセキュリティはどのように記載されているのか」を解説します
|
|