package dbutil import ( "database/sql" "errors" "fmt" "strings" "github.com/go-sql-driver/mysql" ) func OpenMySQLAndCreateDatabaseIfMissing(dsn string) (*sql.DB, error) { db, err := sql.Open("mysql", dsn) if err != nil { return nil, err } if err := db.Ping(); err == nil { return db, nil } else { _ = db.Close() var mysqlErr *mysql.MySQLError if !errors.As(err, &mysqlErr) || mysqlErr.Number != 1049 { return nil, err } } cfg, err := mysql.ParseDSN(dsn) if err != nil { return nil, err } if cfg.DBName == "" { return nil, errors.New("DSN does not include a database name") } databaseName := cfg.DBName cfg.DBName = "" adminDB, err := sql.Open("mysql", cfg.FormatDSN()) if err != nil { return nil, err } defer adminDB.Close() if err := adminDB.Ping(); err != nil { return nil, err } if _, err := adminDB.Exec("CREATE DATABASE IF NOT EXISTS " + QuoteMySQLIdentifier(databaseName) + " CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci"); err != nil { return nil, err } fmt.Printf("created database %q\n", databaseName) db, err = sql.Open("mysql", dsn) if err != nil { return nil, err } if err := db.Ping(); err != nil { _ = db.Close() return nil, err } return db, nil } func QuoteMySQLIdentifier(name string) string { return "`" + strings.ReplaceAll(name, "`", "``") + "`" } func IsDuplicateColumnError(err error) bool { var mysqlErr *mysql.MySQLError return errors.As(err, &mysqlErr) && mysqlErr.Number == 1060 }