CakePHPからMSSQL(SQLServer)に日本語でSELECTをかけるとエラーが出る

CakePHPからMSSQLへのアクセスはFreeTDSやunixODBCを使って実現できたが、いざSELECTをかけるとエラーになる……。なんでだ?いや、うまくいくSELECTとうまくいかないSELECTがある。その違いは……文字列か数値か……いや、日本語を使っているかどうかか……。

SQLServerに詳しい同僚に確認したら、多国語対応文字列としてSQLServerでは「nvarchar」というものが存在するという。単なる可変文字列の「varchar」に対して、nationalを意味する接頭語「n」がついた「nvarchar」の文字列へのSELECTやINSERTなどは、「’ほげほげ’」と指定したい場合には「N’ほげほげ’」と、文字列に対しても接頭語Nが必要になるという。

CakePHPの拡張データソースをGithubから入手できるが、その入手したプラグインを使っても「N」対応はされていない模様。Sqlserver.phpというプラグイン側では「N」対応されているのだが、このプラグインを使うともっと別のエラーが出るので、いま現時点でうまくアクセスができているMssql.phpで「N」対応させてやりたい……ということで、汎用性を失うような作業は避けたかったが泣く泣くプラグインに手を入れることに決めた。

といっても、それほど大きな修正ではない。単に「N」を付けるように仕組んだだけだ。しかも厳密ではない。
以下がdiff。-pでpatch対応させているが、意味と行数がわかれば手動でパッチを当てる方がよいだろう。特にすでにMssql.phpに手を入れいれている場合やバージョン違いなどの場合はpatchが当てられないこともあるので、手動パッチでの対応が求められる。

[shell]
# diff -p Mssql.php.ORG Mssql.php
*** Mssql.php.ORG 2013-05-06 17:28:57.275400492 +0900
— Mssql.php 2013-05-10 11:43:49.769617062 +0900
*************** class Mssql extends NativeDriverSource {
*** 299,304 ****
— 299,306 —-
case ‘boolean’:
$data = $this->boolean((bool)$data);
break;
+ case ‘string’:
+ return "N’" . $data . "’";
default:
if (get_magic_quotes_gpc()) {
$data = stripslashes(str_replace("’", "”", $data));
*************** class Mssql extends NativeDriverSource {
*** 783,786 ****
}
return null;
}
! }
\ No newline at end of file
— 785,788 —-
}
return null;
}
! }

[/shell]

10~11行目の追加は、string型が来たら強引に「N」を付けてしまおうという解決法。これは強引だが、特に問題は出ない。ASCII文字列であってもUTF-8文字列であっても混在であっても有効であることは確認した。
本来であれば文字型を比較したり、もっと別のメソッド内でデータ型を判断している箇所などもあるので(Mssql.phpプラグインは、「~char」というデータ型はすべてstringで扱っているので、nvarcharもstring型と判断される)、本当に手抜きパッチなのであるが、一応これで動作自体問題ないのでヨシとしてしまった。いかんエンジニアだ……よいエンジニアはマネしてはいけません。

コメントを残す

メールアドレスが公開されることはありません。

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください