日本語文字列でLIKE検索を行う場合などのトラブルの回避方法について説明します
日本語データの検索の問題点と対策
- 問題点
DBISAMのSQLエンジンが、日本語SJISのマルチバイト文字を正しく処理できない。
** 症状1)
「表」という文字の2バイト目には「\」と同じ文字コードが入っているため、SELECT FROM ....
WHERE ... LIKE "%\%" が、"表”を含むテキストにヒットしてしまう。** 症状2)
半角カナ、「棒」「ダ」など、一致しないものまでやたらにヒットする。文字列比較にWindowsAPIのCompareStringを呼んでいるのですが
ここで、NORM_IGNORENONSPACE(場所を取らない文字を区別しない)オプションが
セットされており、2バイト文字の1バイト目は無条件に捨てられるという問題が存在します。 - 対策
2-1) DBISAMLb.pas のfunction CompareMBCSCharを以下で置き換えます。
procedure MBCSInc(LocaleID: Integer; var CurPtr: PChar);
begin
if (LocaleID <> LOCALE_ANSI_STD) then
begin
if (StrByteType(CurPtr,0)=mbLeadByte) then
Inc(CurPtr);
if (CurPtr^=#0) then
Exit;
end;
Inc(CurPtr);
end;
function CompareMBCSChar(LocaleID: Word;
FirstChar: PChar; SecondChar: PChar): Integer;
begin
Result:=OSCompareCharNoAccent(LocaleID,FirstChar^,SecondChar^);
if (LocaleID <> LOCALE_ANSI_STD) and (Result=CMP_EQUAL) then
begin
Result := Ord(FirstChar^) - Ord(SecondChar^); //K.Okada 2005/7/3 //*****
if (Result = CMP_EQUAL) and (StrByteType(FirstChar,0)=mbLeadByte) then //*****
begin
Inc(FirstChar);
Inc(SecondChar);
if (FirstChar^=#0) and (SecondChar^=#0) then
Result:=CMP_EQUAL
else if (FirstChar^=#0) and (SecondChar^ <> #0) then
Result:=CMP_LESS
else if (FirstChar^ <> #0) and (SecondChar^=#0) then
Result:=CMP_GREATER
else
Result:=Ord(FirstChar^) - Ord(SecondChar^); //*****
end;
end;
end;
注意
上記の修正を生かすには、テーブルのLOCALEを日本語にする必要があります(デフォルトはANSI_STD)。DBSYSでもセットできますし、SQLのCREATE
TABLE文、ALTER TABLE文にロケール1041を指定してもOKです。
例)
CREATE TABLE IF NOT EXISTS "new" ( "AAA" VARCHAR(10), PRIMARY KEY ("RecordID") COMPRESS NONE LOCALE CODE 1041 );
現在のDBISAMのソースには、米国ElevateSoftによって上記の修正が部分的に反映されていますが、中途半端なので、必ず上記のコードで置き換えてください。特にMBCSInc関数は一見すると似ていますが、よく見ると間違っています。
※日本語対応のための修正を弊社にて行い、時々メールで通知していたのですが、日本語のための修正が他のヨーロッパ言語に悪影響を及ぼす恐れがあり、また現在DBISAMの開発陣は、.NET・Unicodeに対応するVer.5の開発に入っていることもあるため、最新の日本語用修正分については弊社の手許に留めております。
