ユーザー定義関数で日付時刻や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」などを紹介していきます。今回は、「各種ガイドラインが示すコンプライアンス要件に、データベースのセキュリティはどのように記載されているのか」を解説します
|
|




