github.com/go-sql-driver/mysql
(a.k.a. Go-MySQL-Driver)のv1.8.0をリリースしました。
個人的に重要だと思う点を紹介していきます。
charset/collationの扱い
ちょうどGREEさんのBlogで話題になっていた件です。
go-sql-driver/mysql も MySQL 8.0 もデフォルトのままだと、collation_connectionはutf8mb4_general_ci、collation_serverはutf8mb4_0900_ai_ciになります。いずれも character set としてはutf8mb4ですが、utf8mb4_general_ciとutf8mb4_0900_ai_ciは振る舞いが大きく異なるので、Goでutf8mb4を使うなら、意図したcollationが適用されているか注意が必要です。
v1.7まではREADMEに次のように書かれていました。
Version 1.0 of the driver recommended adding
&charset=utf8
(alias forSET NAMES utf8
) to the DSN to enable proper UTF-8 support. This is not necessary anymore. Thecollation
parameter should be preferred to set another collation / charset than the default.
DSNで charset
を指定するのは非推奨で collation
を書け、ということですね。ハンドシェイクではそのcollationに対応したcollation idを使います。 charset
を指定した場合はそのcharsetに対するデフォルトのcollationを選びますし、両方を指定した場合は collation
が優先されました。
これには、 collation を理解して正しく設定しないといけないという問題と、ドライバー側でサーバーと一致したcollationの名前とidのマッピングを持っていないといけないという問題がありました。MySQL 8がどんどん進化する中、MySQLプロトコルを利用する他の製品も多様化していくので、問題は徐々に悪化してきました。
v1.8では charset
を指定したときの動作が変わります。ハンドシェイクでデフォルトのcollation_idを送るのはそのままですが、接続後に SET NAMES <charset>
を実行するので、そのcharsetに対するサーバー側のデフォルトのcollationが利用されます。 skip-character-set-client-handshake
や、指定したcollation_idをサーバーが知らなかったなどの理由で暗黙のうちに完全に無視されることはありません。そのcharsetをサーバーが知らないならちゃんとエラーになります。
ということで、サーバー側のデフォルトのcollationをそのまま使えばいいほとんどのケースで、 charset
のみを指定する設定を推奨します。 collation も指定したい場合は、charsetとcollationの両方を指定してやれば、 SET NAMES <charset> COLLATE <collation>
というクエリを実行するので、確実にそのcollationを使えます。
より詳しい解説を去年Zennで MySQL接続のcollation不整合の原因と対策 という記事を書いたので読んでみてください。
Scan()にanyを渡した時の挙動を改善しました。
v1.7では次のように、内部でテキストプロトコルが使われているかバイナリプロトコルが使われているかでanyにScan()した時の結果が異なりました。
// db の接続設定で interpolateParams が false の場合 var v any db.QueryRow("SELECT 123 WHERE ? = 1", 1).Scan(&v) fmt.Printf("%T %v\n", v, v) // int64 123 db.QueryRow("SELECT 123 WHERE 1 = 1").Scan(&v) fmt.Printf("%T %v\n", v, v) // []uint8 [49 50 51]
整数やfloatなど、変換してもアロケーションが増えない型に限定して、テキストプロトコルでもバイナリプロトコルと同じ結果になるようにしました。
これも詳細は去年Zennに書いたので、Go-MySQL-DriverでScan()にanyを渡した時の挙動を改善しました を読んでみてください。