GoでRDBにアクセスするには標準パッケージのdatabase/sqlを使うわけですが、database/sqlの返すエラーは文字列のエラーメッセージ以上の情報を持っていないので、発生したエラーに応じた処理ということができません。例えばユニーク制約違反をハンドリングしたい場合とか。
エラーメッセージの文字列を見てエラーの種類を判別するということも出来なくはないかもしれませんが、最期の手段にしたいところです。
なにか良い方法ないかなーと検索してみたらこちらのトピックで、ドライバの生成するエラーがdatabase/sqlでラップされないんなら、型アノテーションでエラーを判別できるのでは?というアイデアが挙がっていました。
というわけで、database/sqlのソースを確認してみたところ、ドライバが生成したエラーはラップされずにそのまま返される様子。そして、github.com/go-sql-driver/mysqlにはそのものずばりのmysql.MySQLError
があるではないですか。
というわけで試してみました。
package main
import (
"database/sql"
"log"
"github.com/go-sql-driver/mysql"
)
func main() {
// CREATE TABLE test (i INT PRIMARY KEY);
db, _ := sql.Open("mysql", "foobar")
db.Exec("INSERT INTO test VALUES (1)")
_, err := db.Exec("INSERT INTO test VALUES (1)")
if err != nil {
if mysqlErr, ok := err.(*mysql.MySQLError); ok {
log.Printf("Number: %d", mysqlErr.Number)
log.Printf("Message: %s", mysqlErr.Message)
log.Printf("Error(): %s", mysqlErr.Error())
}
}
}
実行結果
$ go run main.go
2016/06/20 23:55:57 Number: 1062
2016/06/20 23:55:57 Message: Duplicate entry '1' for key 'PRIMARY'
2016/06/20 23:55:57 Error(): Error 1062: Duplicate entry '1' for key 'PRIMARY'
いけました。Number
フィールドにMySQLのエラーコード、Message
フィールドにMySQLのエラーメッセージが入れられているようです。MySQLプロトコルのエラーパケットから取り出された情報のようですね。SQLSTATEに関してはMySQLErrorには含まれないようです
これで詳細なエラー原因を判別することができそうですね。おそらくは保証された動作ではないでしょうから、そこには注意が必要そうですが、文字列で判別するよりは幾分ましかなと。