フォーラム


ゲスト  

ようこそ ゲスト さん。このフォーラムに投稿するには 登録が必要です。

ページ: [1] 2
トピック: FireBirdでSJIS_0208からUTF-8に変更してエラーが
hebo
メンバー
投稿数: 7
FireBirdでSJIS_0208からUTF-8に変更してエラーが
on: 2013/08/07 10:07 Wed

お世話になります。

初めて質問させていただきます。

FireBirdを使用してDelphi XE2で開発しています。
FireBird のバージョンは WI-V2.5.1.26351 Firebird 2.5 になります。

元々SJIS_0208で作成したDBで運用していたのですが、ある項目を曖昧検索していて以下のエラーが出るようになり

Dynamic SQL Error
SQL error code = -303
arithmetic exception, numeric overflow, or string truncation
string right truncation

どうも、機種依存文字が原因のようだと気がついて、UNICODEにすれば直るかと思い、UTF-8でDBを作成して
同じ構造のテーブルを作成してデータをインポートしたところ、malformed stringのエラーが出ました。

対応としてAnsitoUTF8()で文字列を変換したらこのエラーは出なくなったのですが、SJIS_0208で運用していた
時にはインポート時にエラーが出なかったのに、arithmetic exception,・・・・がかなり出るようになりました。

そこで、テーブルの文字列の項目長を倍に変更して再度インポートしても同様のエラーが出てしまい困って
います。エラーメッセージは以前と同様ですが念のため下記に附記しておきます。

Dynamic SQL Error
SQL error code = -303
arithmetic exception, numeric overflow, or string truncation
string right truncation

インポートするデータは基幹システムの1ヶ月分の検収データで数万件になります。
エラーになったレコードの項目値を見ても特に問題になるような所も見あたりませんし、以前SJIS_0208で
作成したDBの時にはエラー無しでインポート出来ていたので、プログラムも変えてませんし、どうして良いか
分らなくなって困っています。

プログラムは、現在テスト中ですので多少いじくっていますが以下の様なプログラムです。

with IBQuery1 do
begin
close;
SQL.Clear;
SQL.Add('INSERT INTO KENSHU (SEIKYU_DENPYOU,TENKI_DATE,KOUBAI_DENPYOU,'+
'MEISAI,QUANTITY,HINMOKU_CD,HINMOKU_TXT,NET_VALUE,CURRENCY,PER,'+
'PAY_BASE_DATE,SUPPLIER_CD,SUPPLIER_NAME,DC,AMOUNT,KOUBAI_GR,KOUBAI_GR_TXT,'+
'PLANT,SASIZU,SMEISAI)');
SQL.Add('VALUES(:P1,:P2,:P3,:P4,:P5,:P6,:P7,:P8,:P9,:P10,:P11,:P12,' +
':P13,:P14,:P15,:P16,:P17,:P18,:P19,:P20)');
ParamByName('P1').AsString := seikyuNo;//AnsitoUTF8(seikyuNo);
ParamByName('P2').AsDateTime := tenkidate;
ParamByName('P3').AsString := koubaiNo;//AnsitoUTF8(koubaiNo);
ParamByName('P4').AsString := meisaigyo;//AnsitoUTF8(meisaigyo);
ParamByName('P5').AsBCD := kazu;
ParamByName('P6').AsString := hin;//AnsitoUTF8(hin);
ParamByName('P7').AsString := hinmei;//AnsitoUTF8(hinmei);
ParamByName('P8').AsBCD := kakaku;
ParamByName('P9').AsString := tuka;//AnsitoUTF8(tuka);
ParamByName('P10').AsInteger := Per;
ParamByName('P11').AsDateTime := payDate;
ParamByName('P12').AsString := vCD;//AnsitoUTF8(vCD);
ParamByName('P13').AsString := vName;//AnsitoUTF8(vName);
ParamByName('P14').AsString := DC;//AnsitoUTF8(DC);
ParamByName('P15').AsBCD := kingaku;
ParamByName('P16').AsString := K_Gr;//AnsitoUTF8(K_Gr);
ParamByName('P17').AsString := K_GrName;//AnsitoUTF8(K_GrName);
ParamByName('P18').AsString := plant;//AnsitoUTF8(plant);
ParamByName('P19').AsString := sasizu;//AnsitoUTF8(sasizu);
ParamByName('P20').AsString := smeisai;//AnsitoUTF8(smeisai);
try
execSQL;
kk := kk + 1;
//MenuForm.IBCTransaction1.Commit;
except
on E: Exception do
begin
err := E.Message;
memo1.Lines.Add(err);
err := vCD + ',' + vName + ',' + seikyuNo + ',' + smeisai + ',' + koubaiNo + ',' + meisaigyo + ',' + hinmei;
memo1.Lines.Add(err);
end;
//MenuForm.IBCTransaction1.Rollback;
end;

end;

なにか、ヒントでも戴けないでしょうか。
どうぞ、宜しくお願いします。

メーカーに勤務する会社員です。
自部署で使用するデータベース(FireBird)のプログラムをDelphiで書いています。

DEKO
管理者
投稿数: 2691
Re: FireBirdでSJIS_0208からUTF-8に変更してエラーが
on: 2013/08/07 10:38 Wed

こんにちは。

引用 hebo on 2013/08/07 10:07 Wed
どうも、機種依存文字が原因のようだと気がついて…

 
もし、機種依存文字の問題なのでしたら、Unicode ではなく CP943C を使ってみてはいかがでしょうか?
また、UTF-8 ではなく UNICODE_FSS を試してみるのもアリかと思います。
(もちろん FDB は新規作成する必要があります)

IBX をお使いのようですが、lc_ctype はちゃんと設定されていますか?

See Also:
[Interbase / Firebird への接続]
http://ht-deko.minim.ne.jp/delphiforum/?vasthtmlaction=viewtopic&t=313

hebo
メンバー
投稿数: 7
Re: FireBirdでSJIS_0208からUTF-8に変更してエラーが
on: 2013/08/07 11:57 Wed

はい、すみません。記入するのを忘れていました。

ご指摘の件については気がついて、クライアントをUTF-8からCP943CにしてみてAnsitoUTF8()を外してもmalformed stringのエラーが
出ない事は確認しました。

それでも-303のエラーが出るのでここに質問させていただきました。

メーカーに勤務する会社員です。
自部署で使用するデータベース(FireBird)のプログラムをDelphiで書いています。

DEKO
管理者
投稿数: 2691
Re: FireBirdでSJIS_0208からUTF-8に変更してエラーが
on: 2013/08/07 19:02 Wed

-303 に関しては、char() または varchar() フィールドを倍のサイズに変更すれば大抵は収まります。
最終的には以下の Firebird FAQ を地道に確認していくしかないかもしれませんね。

[Arithmetic exception, numeric overflow, or string truncation (Firebird FAQ)]
http://www.firebirdfaq.org/faq79/

DEKO
管理者
投稿数: 2691
Re: FireBirdでSJIS_0208からUTF-8に変更してエラーが
on: 2013/08/07 19:25 Wed

データとして ㈱ のような環境依存文字が既に含まれてしまっている場合はちょっと厄介です。
これだとどうやってもインポートに失敗してしまう事があります。

解決方法は 2 つあります。

1.UNICODE_FSS / UTF-8 の別 DB を作り、そちらへインポートする。
但し、事前に機種依存文字を抜いておく必要がある。インポートが完了した後にデータを修正すれば正しく動作する (事が多い)。

2.機種依存文字を "数値文字参照" でエスケープする
機種依存文字を含む文字列を AnsiString <-> Unicode に変換した際に変換に失敗する (? になってしまう) 文字を変換テーブルとして持っておき、これを 数値文字参照に変換 / 逆変換して処理する。

"㈱ほげほげ" という文字列であれば、"&#x????;ほげほげ" のようにして DB へ格納し、Where 句のパラメータも数値文字参照で渡すという方法です。
全部の文字をエスケープするとフィールドサイズに収まりませんので、機種依存文字のみエスケープするといいと思います。

いずれの方法も、Char() / VarChar() フィールドは 2 倍程度のサイズが必要になります。

See Also:
[数値文字参照 (Wikipedia)]
http://ja.wikipedia.org/wiki/%E6%96%87%E5%AD%97%E5%8F%82%E7%85%A7

hebo
メンバー
投稿数: 7
Re: FireBirdでSJIS_0208からUTF-8に変更してエラーが
on: 2013/08/08 10:27 Thu

お世話になります。
 前にも書きましたが項目長に関しては長さを倍にして既に確認しております。

引用 DEKO on 2013/08/07 19:25 Wed
データとして ㈱ のような環境依存文字が既に含まれてしまっている場合はちょっと厄介です。
これだとどうやってもインポートに失敗してしまう事があります。

え、そうなんですか。…<;O_o>

解決方法は 2 つあります。

1.UNICODE_FSS / UTF-8 の別 DB を作り、そちらへインポートする。
但し、事前に機種依存文字を抜いておく必要がある。インポートが完了した後にデータを修正すれば正しく動作する (事が多い)。

データ数が多すぎて手入力での修正は難しいです。

2.機種依存文字を "数値文字参照" でエスケープする
機種依存文字を含む文字列を AnsiString <-> Unicode に変換した際に変換に失敗する (? になってしまう) 文字を変換テーブルとして持っておき、これを 数値文字参照に変換 / 逆変換して処理する。

すみません。この処理の具体的な方法を教えていただけませんか。
それと、どの文字が機種依存文字なのかを判定する簡単な方法とかありますでしょうか。
一体どの項目の文字でエラーになったのかが中々掴みにくいので。

"㈱ほげほげ" という文字列であれば、"&#x????;ほげほげ" のようにして DB へ格納し、Where 句のパラメータも数値文字参照で渡すという方法です。
全部の文字をエスケープするとフィールドサイズに収まりませんので、機種依存文字のみエスケープするといいと思います。

いずれの方法も、Char() / VarChar() フィールドは 2 倍程度のサイズが必要になります。

了解しました。

ところで、機種依存文字に関してはテーブルに保存されていて、問題なく検索も出来ます。例えばⅡなどです。
エラーになった行のデータを見ると半角カタカナが偶に見られますが、全く無い様なレコードもあるので困惑しています。
機種依存文字が原因なのかどうかも、よく分らないんですが。

こんなあやふやな話で申し訳ありません。ただ、他に問題になりそうな事に心当たりも無いのでご相談させていただきました。

See Also:
[数値文字参照 (Wikipedia)]
[url=http://ja.wikipedia.org/wiki/%E6%96%87%E5%AD%97%E5%8F%82%E7%85%A7

]http://ja.wikipedia.org/wiki/%E6%96%87%E5%AD%97%E5%8F%82%E7%85%A7

メーカーに勤務する会社員です。
自部署で使用するデータベース(FireBird)のプログラムをDelphiで書いています。

DEKO
管理者
投稿数: 2691
Re: FireBirdでSJIS_0208からUTF-8に変更してエラーが
on: 2013/08/08 12:56 Thu

-303 の件は 「私が遭遇した問題はこうやって解決しました」 的なものです。
何故そのような事になるのか?なる場合とならない場合の違いは何か?については正直把握していません。

新しい DB (Unicode) を用意し、

  // 古い DB をオープンして回す
while not EOF do
begin
try
// 新しい DB に Insert してみる
except
// エラーレコードのログを取る
end;
Next;
end;

 
このような感じでエラーの出るレコードを地道に調査するのが結局は近道かと思います。

Unicode -> Shift_JIS 変換して変換されない文字については、WideCharToMultiByte() で実際に変換してみるしかありません。
("マップできない文字" という奴です)

[WideCharToMultiByte API]
http://msdn.microsoft.com/ja-jp/library/cc448089.aspx

厳密にはマッピングされなかったものだけが機種依存文字ではないのですが、この作業で問題の出る大抵の文字は洗い出せます。
少なくとも "機種依存文字っぽいものが含まれているレコード" は判断できます。

ところで、機種依存文字に関してはテーブルに保存されていて、問題なく検索も出来ます。例えばⅡなどです。
エラーになった行のデータを見ると半角カタカナが偶に見られますが、全く無い様なレコードもあるので困惑しています。
機種依存文字が原因なのかどうかも、よく分らないんですが。

 
そうなんですよね。規則性があるようでないような感じなんです。
すべての機種依存文字がダメという訳ではなく、"とある条件下で使われている特定の機種依存文字がダメ" みたいな現象だと思うのですが…。

hebo
メンバー
投稿数: 7
Re: FireBirdでSJIS_0208からUTF-8に変更してエラーが
on: 2013/08/08 15:33 Thu

-303 の件は 「私が遭遇した問題はこうやって解決しました」 的なものです。
何故そのような事になるのか?なる場合とならない場合の違いは何か?については正直把握していません。

そうですか。どの項目でのエラーかエラーメッセージで教えてくれると良いんですが。

Unicode -> Shift_JIS 変換して変換されない文字については、WideCharToMultiByte() で実際に変換してみるしかありません。
("マップできない文字" という奴です)

[WideCharToMultiByte API]
http://msdn.microsoft.com/ja-jp/library/cc448089.aspx

やってみます。というか、出来るかな(^^;)
いまいち、使い方が理解できないかも。

そうなんですよね。規則性があるようでないような感じなんです。
すべての機種依存文字がダメという訳ではなく、"とある条件下で使われている特定の機種依存文字がダメ" みたいな現象だと思うのですが…。

そうですか、時間は掛かると思いますが頑張ってみます。

色々、お時間を取ってしまいました。ありがとうございました。

メーカーに勤務する会社員です。
自部署で使用するデータベース(FireBird)のプログラムをDelphiで書いています。

hebo
メンバー
投稿数: 7
Re: FireBirdでSJIS_0208からUTF-8に変更してエラーが
on: 2013/08/08 17:03 Thu

Unicode -> Shift_JIS 変換して変換されない文字については、WideCharToMultiByte() で実際に変換してみるしかありません。
("マップできない文字" という奴です)

すみません。やはり、このやり方が今ひとつ理解できません。
お手数ですが、使い方をご教授戴けますでしょうか。

メーカーに勤務する会社員です。
自部署で使用するデータベース(FireBird)のプログラムをDelphiで書いています。

DEKO
管理者
投稿数: 2691
Re: FireBirdでSJIS_0208からUTF-8に変更してエラーが
on: 2013/08/09 10:25 Fri

Shift_JIS に存在しない文字が "含まれているかどうか" は以下のようなコードで調べる事ができます。

  function RoundTripCheck(s: string): Boolean;
begin
result := (s = string(AnsiString(s)));
end;

 
WideCharToMultiByte() を使っても同じ結果が得られますが、WideCharToMultiByte() だと文字位置を知る事もできます。ある程度の機種依存文字もチェックできますが、①等は OK になってしまいます。実際には①は機種依存文字なのですが、Windows では正しくマッピングされます。

機種依存文字には 2 つあって、一つは ANSI <-> Unicode でマッピングできないもの、もう一つはベンダ依存でマッピング位置が異なったりそもそも文字が割り当てられていないというものです。上のコードは前者を判定するものです。

"WideCharToMultiByte() API の使い方" に関しては Mr.XRAY さんトコにサンプルがあったかと思います。

[885_Win32 API の関数を使用した文字コードの変換]
http://mrxray.on.coocan.jp/Delphi/plSamples/885_MojiCodeWin32API.htm

このトピックの一連の流れからすると以下のようなコードになるかと思います。

  function UnicodeToANSI(s: string): AnsiString;
var
BufSize: Integer;
DefaultChar: AnsiChar;
begin
DefaultChar := #$80; // 変換に失敗する文字の代替文字 (標準だと '?' が設定される)
BufSize := WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, PWideChar(s), -1 , nil, 0, nil, nil);
SetLength(result, BufSize - 1);
WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, PWideChar(s), -1 , PAnsiChar(result), BufSize, @DefaultChar, nil);
end;

 
こちらのコードでも先に挙げた 2 つの機種依存文字のうち、後者は判断できないんですけどね。

ページ: [1] 2
WP Forum Server by ForumPress | LucidCrew
バージョン: 1.7.5 ; ページロード: 0.053 sec.