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}