character_set_results=sjisを発行した上でcp932なテーブルへアクセス
Connector/NETのデフォルトの状態,つまり"character_set_results=NULL"でcp932なテーブルへアクセスするとサーバから返ってくるパケットの解析時にcp932を処理できなくてエラーが起きると以前のエントリで書いたと思う.
そこでテーブルはcp932で作りつつ,character_set_results=sjisを指定してMySQLサーバ側に結果データを"cp932→sjis"にコンバートさせてsjisとしてパケットを返すようにしたらどうなるかを実験.まあ理屈では上手くいくはず.
ソースはこちら
using System; using MySql.Data.MySqlClient; namespace CNTNS { class ConnectorNETTest { public static void Main() { Console.WriteLine("Hello World!"); string myConnectionString = "server=127.0.0.1;uid=root;" + "pwd=;database=test;charset=sjis"; MySqlConnection conn = new MySqlConnection(); conn.ConnectionString = myConnectionString; conn.Open(); MySqlDataReader reader = null; MySqlCommand cmd = null; cmd = new MySqlCommand("set character_set_results=sjis", conn); reader = cmd.ExecuteReader(); reader.Close(); cmd = new MySqlCommand("DROP TABLE IF EXISTS t1", conn); reader = cmd.ExecuteReader(); reader.Close(); cmd = new MySqlCommand("CREATE TABLE t1 (c1 INT, c2 CHAR(1)) DEFAULT CHARSET=cp932", conn); reader = cmd.ExecuteReader(); reader.Close(); cmd = new MySqlCommand("INSERT INTO t1 VALUES (1, '1')", conn); reader = cmd.ExecuteReader(); reader.Close(); cmd = new MySqlCommand("INSERT INTO t1 VALUES (2, 'ァ')", conn); reader = cmd.ExecuteReader(); reader.Close(); cmd = new MySqlCommand("INSERT INTO t1 VALUES (3, 'あ')", conn); reader = cmd.ExecuteReader(); reader.Close(); cmd = new MySqlCommand("INSERT INTO t1 VALUES (4, '㈱')", conn); reader = cmd.ExecuteReader(); reader.Close(); cmd = new MySqlCommand("SELECT * FROM t1", conn); reader = cmd.ExecuteReader(); while (reader.Read()) { Console.WriteLine(reader.GetString(0) + "=" + reader.GetString(1)); } reader.Close(); conn.Close(); Console.WriteLine("Hello MySQL!"); } } }
実行結果
D:\share\workspace\current\CSharp>ConnectorNETTest.exe Hello World! 1=1 2=ァ 3=あ 4=? Hello MySQL!
そのときのGeneral Log
1 Connect root@localhost on test 1 Query SHOW VARIABLES 1 Query SHOW COLLATION 1 Query SET NAMES sjis;SET character_set_results=NULL 1 Init DB test 1 Query set character_set_results=sjis 1 Query DROP TABLE IF EXISTS t1 1 Query CREATE TABLE t1 (c1 INT, c2 CHAR(1)) DEFAULT CHARSET=cp932 1 Query INSERT INTO t1 VALUES (1, '1') 1 Query INSERT INTO t1 VALUES (2, 'ァ') 1 Query INSERT INTO t1 VALUES (3, 'あ') 1 Query INSERT INTO t1 VALUES (4, '㈱') 1 Query SHOW WARNINGS 1 Query SELECT * FROM t1
ふむ.実行結果では文字化けしている.General Logでは文字化けしていないのでとりあえずMySQLServerへは無事届けられたようだ.
General Logを良く見てみると"SHOW WARNING"の文が入っている.MySQLでは文字が変換中に破壊(Truncate)されるとWARNINGがでる.C/NETはそれを拾うためにこの"SHOW WARNIG"を発行しているものと思われる.
ということでサーバ側を覗いてみる.
mysql> set names cp932; Query OK, 0 rows affected (0.00 sec) mysql> select * from t1; +------+------+ | c1 | c2 | +------+------+ | 1 | 1 | | 2 | ァ | | 3 | あ | | 4 | ? | +------+------+ 4 rows in set (0.00 sec) mysql> select hex(c2) from t1; +---------+ | hex(c2) | +---------+ | 31 | | 8340 | | 82A0 | | 3F | +---------+ 4 rows in set (0.00 sec)
hexで"3F"となっているものは半角はてなマーク"?"であり,INSERT時に文字が壊れた場合にこれが現れる.MySQLがsjisからcp932へ括弧株を変換できなかったために起きたものだ.
となるとこれはどういう意味になるだろうか.
- Connector/NETはsjisを使うことで括弧株などの文字もちゃんと扱えるものの
- Connector/NETから既存のcp932テーブルは十分には扱えない
- 別のJavaなサブシステムがcp932テーブルを使っている場合,そのテーブルを.NETなサブシステムと共有できないことになる
とりあえず思いつくのはこういう問題.
さてここらでもう一度自分的にsjisとcp932を整理する必要がありそうだ.