- ベストアンサー
Perl<->Oracle間での文字化けについて
初投稿になります。過去ログを検索したのですが、似た質問はあるものの根本的な解決につながらなかったので、新規の投稿をさせていただきました。 乱文ご容赦ください。 今現在Oracleサーバ上でPerlのプログラムを組んでいます。とは言えPerlも既存の物を改変できる程度の知識ですし、DBに関しての知識はほぼ皆無です。 それでもNet等を参照しながら、どうにかDB内を参照できるようにはなってきました。が、ここで日本語の取り扱いについて突き当たってしまいました。 まずは以下のPerlファイルをご覧ください。 #ソースの前後は割愛 #DBに接続した後のソース # 読み込みcharセットの宣言 $dbh->do("set names 'ujis'"); # 動的SQL文の発行 $hSt = $dbh->prepare(" SELECT * FROM DDD WHERE EEE='100001' "); # 実行 $nRes = $hSt->execute; # データ取得 while($raRes = $hSt->fetchrow_arrayref) { print join(",", @$raRes), "\n"; #","区切りで出力 } #実行すると DBD::Oracle::db do failed: ORA-00922: ??????????????????????? (DBD ERROR: error possibly near <*> indicator at char 4 in 'set <*>names 'ujis'') [for statement ``set names 'ujis''']) at ./test.pl line 18. ,???????,ABC,??? ??152 ,???? ,??????????123,03-xxxx-xxxx ... #表示された内容部分はもっと多くのデータでしたが省略してあります と、散々な結果でした・・・(;^_^ A どなたか解決方法を教えていただけますか? あ、最後になりますが環境です。 サーバ: Oracle9 Perl5.8.0 ソース全体は以下のtxtファイルを参照してください。 ttp://briefcase.yahoo.co.jp/bc/urd_apple/
- みんなの回答 (3)
- 専門家の回答
質問者が選んだベストアンサー
perl5.8で、DBI+DBD-ORACLEが動作したっけ? っていう疑問はあるんですが、きっと今は動くのですよね。 >$dbh->do("set names 'ujis'"); オラクルは、そのようなSQLを投げられても処理できません。 今は、これが邪魔してエラーになっています。 基本的に、オラクルサーバ-クライアントの文字コード処理は、NLSが自動で行います。 perlが動作する環境のNLS_LANGに従って変換された日本語文字が受け取れる仕組みです。 (文字コードがあっているかどうかはともかく、それで受け取れる) もし、オラクルクライアントの設定と違った文字コードで無理矢理受け取りたいなら、 コネクト前に、 $ENV{'nls_lang'}="JA16SJIS"; とか $ENV{'nls_lang'}="JA16EUC"; とすれば、SJISやEUCで受け取れるハズです。 他にも、SQL文の投入でも一時的変更は可能なハズですが。
その他の回答 (2)
- osamuy
- ベストアンサー率42% (1231/2878)
Oracleなら、環境変数NLS_LANGを指定してみては。 > set names 'ujis' は、MySQLの作法みたいですが。
- 参考URL:
- http://ash.jp/db/ora_nls.htm
お礼
回答ありがとうございます。 そうですか... 「set names 'ujis'」は、MySQLの作法ですか... ...って恥ずっ!! そんなことさえも知らなかった(汗 環境変数ってことは、Oracle側での設定なんですかね?それともPerl文内でsql文を実行して設定できるものなのかしらん... ちょっと調べてみます。
補足
そもそも基本的にOracle側をこちらでいじることができないんです(T-T) しかも以下のページにある通り、サーバ自体を再起動的な方法は、権限として与えられていないのでどうにもこうにも... http://ml.php.gr.jp/pipermail/php-users/2003-August/018035.html
- agharta
- ベストアンサー率52% (54/103)
とりあえず、変数の中身はUTFのままで、出力する際に希望のコードに変更してみては如何ですか。 Jcode.pm等が使えれば、プログラムの最初の方で use Jcode; として、$pre_strの文字列をeucに変更するには my $after_str = Jcode->new($pre_str)->euc; 等とすればいいのではないでしょうか。 また、fetchrow_arrayrefはリターン値がリファレンスの配列です。 すなわち、ここで言うところの$raResはリファレンスです。 使い方としては、$raRes->{"column_name"}ではないでしょうか。 この例だとDDDテーブルにおいてEEEカラムが'100001'の全てのカラムを出すと言うことですよね。少なくともカラム名がEEEなので$raRes->{"EEE"}と言うように使います。 もしくは、fetchrow_arrayを使用するかですね。 参考になれば良いのですが…
お礼
回答ありがとうございます。 社内での出来事でしたので、今現在作業できませんが、来週早速試してみます。(家に同じ環境があればイイんですが、そんな・・・Oracleなんて買えないし・・・( ̄▽ ̄;)) あ、ちなみにモジュールではなくjcode.plは管理者に入れてもらってあるのですが、そっちを使うことも可能ですか? さらに・・・ >また、fetchrow_arrayrefはリターン値がリファレンスの配列です。(以降) DB関係ズブの素人なので、チンプンカンプンです(T^T)(これから勉強してみます) ごめんなさい。このスクリプトもDBとの接続やらデータの取得やらに関しては、他人のスクリプトの流用なので・・・(恥)
補足
(T-T)ダメでしたぁ... jcode.plは置いてあるので、それを使用して... 18 while(@row = $sth->fetchrow_array) 19 { 20 @before_str = @row; 21 print "@row\n"; 22 } 23 24 my $str_code = jcode::getcode($before_str[16]); 25 my $after_str = jcode::convert($before_str[16]); 26 print $before_str[16],"\n"; 27 print $str_code,"\n"; 28 print $after_str,"\n"; #$before_str[16]は、下の結果を見てもわかる通り「??????? 」と、確実に化けているデータを持つ変数です。 で、結果は... Use of uninitialized value in pattern match (m//) at ./jcode.pl line 362. Use of uninitialized value in pattern match (m//) at ./jcode.pl line 362. ??????? Use of uninitialized value in print at ./test2.pl line 27. Use of uninitialized value in print at ./test2.pl line 28. んで、結果からして「おそらく」というお話なんですが、Perl側のeuc-jpのソース上で、すでに化けた状態でjcodeに渡されているために、正規表現のパターンに引っかかっていないんだと思うんですよね。 なので、最初から化けないようにデータを持ってくる必要がありそうなんですが... Perl文上から何かsql文を発行して、持ってくる段階で化けないようにする方法ってないものですかねぇ?
お礼
回答ありがとうございますm(_ _)m osamuyさんやkorochanさんの言われる通り、Oracleから持ってきたデータがTelnet上で化けているというのはNLS_LANGのせいでした。 本当にありがとうございました。 Telnet上で export NLS_LANG=japanese.JAPAN.JA16SJISTILDE とすることで、一時的にクライアント側のNLS_LANGを書き換えたら問題なくSJISで行けました。 とりあえず.bash_prof(だったかな?)にその旨書き込んで、毎回問題なくTelnet接続でいろいろやれております。 お騒がせしました。ありがとうございましたm(_ _)m