プロが教えるわが家の防犯対策術!

Perl+DBI+PostgreSQLでCGIを作っているのですが、Shift-JIS固有の字を扱いたいので、

 SET CLIENT_ENCODING TO 'SJIS';

としたのですが、特定の文字列でSQL文がエラーになります。
例えば「ソ」を

 $str = $dbh->quote( 'ソ' );

とすると、$strは「'ソ\'」になるのですが、これをSQL文中で使用すると、

 DBD::Pg::st execute failed: ERROR: unterminated quoted string at or near "'ソ\' )" at character 124

となってしまいます。
どうやら「2バイト目が5Ch(半角の\)の全角文字」+「\」+「'」と言う組み合わせの時だけエラーになるようです。
ちなみにWindows上のMySQLでは「'ソ\'」で問題ありませんでした。

これはどのように対処すればよろしいのでしょうか?
OSはRed Hat Enterprise Linux ES release 3 (Taroon Update 4) カーネル 2.4.21-4.EL
DBはPostgreSQL 7.4.7です。

よろしくお願いします。

A 回答 (3件)

試しに当方の環境で試してみましたが「濱」をInsertしてHTMLで表示という流れは問題ありませんでした。


当然WHERE句に指定しても問題ありませんでした。
データベースのEncodeはEUCでHTMLはS-JISです。
SJIS表示できるターミナルでも試したのですが、最初ターミナルをEUC表示でSET CLIENT_ENCODING TO 'SJIS';を行い、ターミナルをSJIS表示に切り替えINSERTおよびSELECTしてみましたが問題ありませんでした。ターミナル上でも同様の現象が発生しますか?

この回答への補足

検証ありがとうございます。
SJISターミナルにおいてもやはり「'ソ\'」はエラーでした。「濱」の異体字(ウ冠と貝の間がちょっと違う)や「崎」の異体字(大の所が立になっている)といった文字自体そのものは問題ないのですが、それらの文字を扱う為にShift-JISにしたところ、別の「ソ」「表」「能」といった2バイト目が5Chの文字とシングルクォートの組み合わせがエラーになってしまうのです。

ちなみにこのOKWeb(教えてgoo)もこれらの文字は入力出来ないみたいですね。
Web上ではあまり歓迎されていないのでしょうか…。

補足日時:2005/04/11 12:43
    • good
    • 0

違うかもしれませんが・・・


データベースのEncodeがSQL_ASCIIになってませんか?
前に似たようなことになったことがあるのですがSQL_ASCIIだと
SET CLIENT_ENCODING TO 'SJIS';
を行ってもSJISにはなりません。
その時はEUCに変換するプログラムを作って新たなデータベース(EUC)を作成して対応しました。

この回答への補足

アドバイス、どうもありがとうございました。
「psql -l」で見た所、EncodingはEUC_JPになっていました。
Shift-JISにしたいのは、人名でEUCにはない漢字を扱いたいからなのですが(「濱」や「崎」の異体形)、こういう苗字の人には我慢してもらうしかないのでしょうか…。あと、私の場合はこの環境でしか検証出来ないのですが、この現象がここだけなのか、他のDB環境でも再現されるものなのかが気になります。

引き続き自分でも色々調べています。

補足日時:2005/04/07 17:33
    • good
    • 0

そもそもこの場合は「ソ」をquoteに掛ける必要がないでしょう。


ダブルクォートで括っている場合は展開されてしまうために「ソ」の2バイト目が\であるため文字化けしてしまいますが、シングルクォートで括った場合は展開されないので文字化けが起きません。
今回の場合、「ソ\」で2バイト目の\とquoteで付加された\で\\と続いてしまっているために打ち消されて\ひとつになってしまいエラーの原因になっていると思われます。
(Perlでは\\は文字としての\を表します)

この回答への補足

早速のアドバイス、どうもありがとうございます。
非常に役に立ちました。

ただ、文字列をSQL文内にセットする時にquoteを通さないのはあまり現実的でないような気がします。
例えばファイルを1行づづ読み込んでDBに挿入するのはよくある事だと思うのですが、1行目が「\」、2行目が「ソ」だった場合、前者はquoteを通さないとエラーになり、後者は通すとエラーになります。
通すか通さないかを判断するには文字列のバイトイメージをいちいち解析しなければならず、quote後はそれぞれ「'\\'」「'ソ\'」16進で(27 5C 5C 27) (27 83 5C 5C 27)になりますが、単に「\\'」の並びではエラーにならず、あくまで最初の「\」が「全角文字の2バイト目」の時に限ってエラーになります。
ですから「ソセ」→「'ソ\セ'」(27 83 5C 5C 83 5A 27)のように「\」と「'」が離れている時はうまく行きます。
私としては、「\\'」において1番目の「\」が単体の時は「\\」の方が「\'」よりも優先順位が高く、全角後半の時は「\\」よりも「\'」の方が高い為にこのようになってしまうのかな?とも思ったのですが。

ちなみにPerlはシングルクォートで囲む場合でも、クォートの直前に5Chが来る全角文字では「'ソ'」ではなく「'ソ\'」としないとエラーになりました。
私も自分で色々調べているのですが、よろしくお願いします。

補足日時:2005/04/05 17:38
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!