001package io.ebean.docker.commands;
002
003import io.ebean.docker.container.Container;
004
005import java.sql.Connection;
006import java.sql.SQLException;
007import java.util.List;
008import java.util.Properties;
009
010public class MySqlContainer extends JdbcBaseDbContainer implements Container {
011
012  public static MySqlContainer create(String mysqlVersion, Properties properties) {
013    return new MySqlContainer(new MySqlConfig(mysqlVersion, properties));
014  }
015
016  public MySqlContainer(MySqlConfig config) {
017    super(config);
018  }
019
020  @Override
021  void createDatabase() {
022    createRoleAndDatabase(false);
023  }
024
025  @Override
026  void dropCreateDatabase() {
027    createRoleAndDatabase(true);
028  }
029
030  private void createRoleAndDatabase(boolean withDrop) {
031    try (Connection connection = config.createAdminConnection()) {
032      if (withDrop) {
033        dropUserIfExists(connection, dbConfig.getUsername());
034        dropDatabaseIfExists(connection, dbConfig.getDbName());
035      }
036      createDatabase(connection);
037      createUser(connection);
038
039    } catch (SQLException e) {
040      throw new RuntimeException("Error when creating database and role", e);
041    }
042  }
043
044  private void createUser(Connection connection) {
045    createUser(connection, dbConfig.getUsername(), dbConfig.getPassword(), dbConfig.getDbName());
046  }
047
048
049  private void dropDatabaseIfExists(Connection connection, String dbName) {
050    if (databaseExists(connection, dbName)) {
051      sqlRun(connection, "drop database " + dbName);
052    }
053  }
054
055  private void dropUserIfExists(Connection connection, String username) {
056    if (userExists(connection, username)) {
057      sqlRun(connection, "drop user '" + username + "'@'%'");
058    }
059  }
060
061  private void createUser(Connection connection, String dbUser, String dbPassword, String db) {
062    if (!userExists(connection, dbUser)) {
063      sqlRun(connection, "create user '" + dbUser + "'@'%' identified by '" + dbPassword + "'");
064      sqlRun(connection, "grant all on " + db + ".* to '" + dbUser + "'@'%'");
065    }
066  }
067
068  private void createDatabase(Connection connection) {
069    if (!databaseExists(connection, dbConfig.getDbName())) {
070      createDatabase(connection, dbConfig.getDbName());
071      if (!dbConfig.version.startsWith("5")) {
072        setLogBinTrustFunction(connection);
073      }
074    }
075  }
076
077  private void setLogBinTrustFunction(Connection connection) {
078     sqlRun(connection, "set global log_bin_trust_function_creators=1");
079  }
080
081  private void createDatabase(Connection connection, String dbName) {
082    sqlRun(connection, "create database " + dbName);
083  }
084
085  private boolean databaseExists(Connection connection, String dbName) {
086    return sqlHasRow(connection, "show databases like '" + dbName + "'");
087  }
088
089  private boolean userExists(Connection connection, String dbUser) {
090    return sqlHasRow(connection, "select User from user where User = '" + dbUser + "'");
091  }
092
093  @Override
094  protected ProcessBuilder runProcess() {
095
096    List<String> args = dockerRun();
097    if (defined(dbConfig.getAdminPassword())) {
098      args.add("-e");
099      args.add("MYSQL_ROOT_PASSWORD=" + dbConfig.getAdminPassword());
100    }
101    args.add(config.getImage());
102
103    if (config.isDefaultCollation()) {
104      // leaving it as mysql server default
105
106    } else if (config.isExplicitCollation()) {
107      String characterSet = config.getCharacterSet();
108      if (characterSet != null) {
109        args.add("--character-set-server=" + characterSet);
110      }
111      String collation = config.getCollation();
112      if (collation != null) {
113        args.add("--collation-server=" + collation);
114      }
115    } else {
116      args.add("--character-set-server=utf8mb4");
117      args.add("--collation-server=utf8mb4_bin");
118    }
119    if (!dbConfig.version.startsWith("5")) {
120      args.add("--default-authentication-plugin=mysql_native_password");
121    }
122
123    return createProcessBuilder(args);
124  }
125
126}