ユーザー定義関数で日付時刻やBLOBを扱う
アナハイムテクノロジー
はやしつとむ
2009/7/21
BLOB UDFのサンプル(1)
それでは、BLOBを扱うUDFの例を見ていきましょう。まずは、Ian Newby氏作のBLOB UDFsから、一番簡単なサンプルを示します。
wmudflib.c(35) long EXPORT fn_blob_length (ARG(BLOB, sourceBlob)) ARGLIST(BLOB sourceBlob) { if (!sourceBlob->blob_handle) { return 0L; } return (sourceBlob->blob_total_length); }
blob_handleがNULLであれば、0を返して抜けます。そうでない場合は、sourceBlobのblob_total_lengthを返すというものです。
Delphiで同じことをやってみます。
library UDF_sample3; uses SysUtils, IBExternals; {$R *.res} function tomneko_blob_length(SourceBlob:PBlob):Integer;stdcall; begin Result := 0; if (SourceBlob^.BlobHandle^ = 0) then Exit else Result := SourceBlob^.TotalSize; end; exports tomneko_blob_length; begin end.
●登録用スクリプト:
DECLARE EXTERNAL FUNCTION tomneko_blob_length BLOB RETURNS INTEGER BY VALUE ENTRY_POINT 'Tomneko_Blob_Length' MODULE_NAME 'UDF_sample3.dll';
●使用例:
SQL> SELECT TOMNEKO_BLOB_LENGTH(BLOB1) FROM T_BLOB; TOM_BLOB_LENGTH =============== 89334 89334 89334 89334 89334
BLOB UDFのサンプル(2)
次に、同じくIan Newby氏作のBLOB UDFsから、BLOBから文字列への変換を行うUDFと、逆に文字列からBLOBを返すUDFを見てみます。
wmudflib.c(100) char* EXPORT fn_blob_string(ARG(BLOB, sourceBlob), ARG(char*, sResult)) ARGLIST(BLOB sourceBlob) ARGLIST(char *sResult) { long start; long end; start = 1; end = fn_blob_length(sourceBlob); fn_blob_substr(sourceBlob, &start, &end, sResult); return sResult; }
fn_blob_string()関数は、BLOBを文字列として返します。実際にBLOBに格納されているデータが文字列かどうかの判断はしていないので、注意が必要です。
内容的には、先ほど示したfn_blob_length()関数を使ってblobの長さを得てから、fn_blob_substr()関数を利用して最初から最後までのデータを取り出しています。fn_blob_substr()関数は以下のような内容です。
wmudflib.c(47) char* EXPORT fn_blob_substr(ARG(BLOB, sourceBlob), ARG(long*, startPos), ARG(long*, endPos), ARG(char*, sResult)) ARGLIST(BLOB sourceBlob) ARGLIST(long *startPos) ARGLIST(long *endPos) ARGLIST(char *sResult) { char *pbuffer, *pOffset, *pResultOffset; long i = 0; long curr_bytecount = 0; long startChar, endChar; long length, actual_length; *sResult = 0; if (!sourceBlob->blob_handle) { return sResult; } length = sourceBlob->blob_max_segment; if (*startPos > *endPos || *startPos < 1L || *endPos < 1L) { return sResult; } if (sourceBlob->blob_total_length < (long)*startPos) { return sResult; } startChar = *startPos; if (sourceBlob->blob_total_length < (long)*endPos) { endChar = sourceBlob->blob_total_length; } else { endChar = *endPos; } pbuffer = (char *) malloc (length + 1L); pResultOffset = sResult; while ((*sourceBlob->blob_get_segment) (sourceBlob->blob_handle, pbuffer, length, &actual_length)) { // pbuffer [actual_length] = 0; pOffset = pbuffer; while (*pOffset && (curr_bytecount < endChar)) { curr_bytecount++; if (curr_bytecount >= startChar) { *pResultOffset++ = *pOffset; } pOffset++; } if (curr_bytecount >= endChar) { *pResultOffset = 0; break; } } free (pbuffer); return sResult; }
fn_blob_substr()関数では、引数のチェックを行ったあと、sourceBlobで渡されたBLOB制御構造体のblob_get_segmentを利用して、BLOBのデータを取り出し、sResultで渡される戻り値へコピーを行っています。blog_get_segment()はBLOBを最後まで読み出すと0を返すので、それを見ながらループすればいいわけです。
wmudflib.c(153) BLOB EXPORT fn_string_blob(ARG(char*, sourceString), ARG(BLOB, sResult)) ARGLIST(char *sourceString) ARGLIST(BLOB sResult) { (*sResult->blob_put_segment) (sResult->blob_handle, sourceString, strlen(sourceString)); return sResult; }
fn_string_blob()関数は、単純に、BLOB制御構造体のblob_put_segment()関数を利用して、BLOBにデータを書き込んでFirebirdへ返しているだけです。
それでは、これらを先ほどのUDF_sample3に追加してみましょう。Delphi2009に対応するため、PCharではなくPAnsiCharを使用し、必要な個所でPByteへのキャストを行っています。C/C++からのポーティングは多少面倒になってしまったようです。
library UDF_sample3; uses SysUtils, IBExternals; {$R *.res} function Tomneko_Blob_Length(SourceBlob:PBlob):Integer;stdcall; begin Result := 0; if (SourceBlob^.BlobHandle^ = 0) then Exit else Result := SourceBlob^.TotalSize; end; Procedure Tomneko_Blob_substr(SourceBlob:PBlob; var startPos, endPos:Integer; sResult:PAnsiChar);stdcall; var pbuffer, pResultOffset, pOffset:PAnsiChar; curr_bytecount, startChar, endChar, length, actual_length:Integer; begin curr_bytecount := 0; sResult^ := #0; if (sourceBlob^.BlobHandle^ = 0) then begin Exit; end; length := sourceBlob^.MaxSegmentLength; if ((startPos > endPos) or (startPos < 1) or (endPos < 1)) then begin exit; end; if (sourceBlob^.TotalSize < startPos) then begin exit; end; startChar := startPos; if (sourceBlob^.TotalSize < endPos) then begin endChar := sourceBlob^.TotalSize; end else begin endChar := endPos; end; GetMem(pbuffer, length + 1); pResultOffset := sResult; while (sourceBlob^.GetSegment(sourceBlob^.BlobHandle, PByte(pbuffer), length, actual_length) <> 0) do begin pOffset := pbuffer; while ((pOffset <> #0) and (curr_bytecount < endChar )) do begin Inc(curr_bytecount); if (curr_bytecount >= startChar ) then begin pResultOffset^ := pOffset^; inc(pResultOffset); end; Inc(pOffset); if (curr_bytecount = actual_length) then Break; end; if (curr_bytecount >= endChar) then begin pResultOffset^ := #0; break; end; end; freeMem(pbuffer); exit; end; Procedure Tomneko_Blob_string(sourceBlob:PBlob; sResult:PAnsiChar);stdcall; var startPos, endPos:Integer; begin startPos := 1; endPos := Tomneko_blob_length(sourceBlob); Tomneko_blob_substr(sourceBlob, startPos, endPos, sResult); end; Procedure Tomneko_string_Blob(sourceString:PAnsiChar; sResult:PBlob);stdcall; begin sResult^.PutSegment(sResult^.BlobHandle, PByte(sourceString), strlen(PChar(sourceString))); end; exports Tomneko_Blob_Length, Tomneko_Blob_substr, Tomneko_Blob_string, Tomneko_string_Blob; end.
登録用スクリプト:
DECLARE EXTERNAL FUNCTION TOMNEKO_BLOB_SUBSTR BLOB, INTEGER, INTEGER, CSTRING(256) CHARACTER SET UTF8 RETURNS PARAMETER 4 ENTRY_POINT 'Tomneko_Blob_substr' MODULE_NAME 'UDF_sample3'; DECLARE EXTERNAL FUNCTION TOMNEKO_BLOB_TO_STRING BLOB, CSTRING(256) CHARACTER SET ASCII RETURNS PARAMETER 2 ENTRY_POINT 'Tomneko_Blob_string' MODULE_NAME 'UDF_sample3'; DECLARE EXTERNAL FUNCTION TOMNEKO_STRING_TO_BLOB CSTRING(32000) CHARACTER SET ASCII, BLOB RETURNS PARAMETER 2 ENTRY_POINT 'Tomneko_string_Blob' MODULE_NAME 'UDF_sample3';
●使用例:
SQL> CREATE TABLE T_BLOB (BLOB1 BLOB SUB_TYPE 1); SQL> INSERT INTO T_BLOB VALUES (TOMNEKO_STRING_TO_BLOB('TOMNEKO')); SQL> SELECT TOMNEKO_BLOB_TO_STRING(BLOB1) FROM T_BLOB; TOMNEKO_BLOB_TO_STRING ================== TOMNEKO
3/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」などを紹介していきます。今回は、「各種ガイドラインが示すコンプライアンス要件に、データベースのセキュリティはどのように記載されているのか」を解説します
|
|