• 締切済み

quoteした文字列を使ったSQL文がエラーになってしまいます

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です。 よろしくお願いします。

みんなの回答

  • nya0124
  • ベストアンサー率0% (0/1)
回答No.3

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

noname#199420
質問者

補足

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

すると、全ての回答が全文表示されます。
  • nya0124
  • ベストアンサー率0% (0/1)
回答No.2

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

noname#199420
質問者

補足

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

すると、全ての回答が全文表示されます。
  • Ethersky
  • ベストアンサー率71% (168/235)
回答No.1

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

noname#199420
質問者

補足

早速のアドバイス、どうもありがとうございます。 非常に役に立ちました。 ただ、文字列を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が来る全角文字では「'ソ'」ではなく「'ソ\'」としないとエラーになりました。 私も自分で色々調べているのですが、よろしくお願いします。

すると、全ての回答が全文表示されます。

関連するQ&A