日本語文字列で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の開発に入っていることもあるため、最新の日本語用修正分については弊社の手許に留めております。