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
010/**
011 * Commands for controlling a SqlServer docker container.
012 */
013public class SqlServerContainer extends JdbcBaseDbContainer implements Container {
014
015  public static SqlServerContainer create(String version, Properties properties) {
016    return new SqlServerContainer(new SqlServerConfig(version, properties));
017  }
018
019  public SqlServerContainer(SqlServerConfig config) {
020    super(config);
021  }
022
023  @Override
024  void createDatabase() {
025    createRoleAndDatabase(false);
026  }
027
028  @Override
029  void dropCreateDatabase() {
030    createRoleAndDatabase(true);
031  }
032
033  private void createRoleAndDatabase(boolean withDrop) {
034    try (Connection connection = config.createAdminConnection()) {
035      if (withDrop) {
036        dropDatabaseIfExists(connection);
037      }
038      createDatabase(connection);
039      createLogin(connection);
040      createUser();
041
042    } catch (SQLException e) {
043      throw new RuntimeException("Error when creating database and role", e);
044    }
045  }
046
047  private void createUser() {
048    try (Connection dbConnection = dbConfig.createAdminConnection(dbConfig.jdbcUrl())) {
049      createUser(dbConnection);
050    } catch (SQLException e) {
051      throw new RuntimeException(e);
052    }
053  }
054
055  private void createLogin(Connection connection) {
056    if (!loginExists(connection, dbConfig.getUsername())) {
057       createLogin(connection, dbConfig.getUsername(), dbConfig.getPassword());
058    }
059  }
060
061  private void createUser(Connection dbConnection) {
062    if (!userExists(dbConnection, dbConfig.getUsername())) {
063      createUser(dbConnection, dbConfig.getUsername(), dbConfig.getUsername());
064      grantOwner(dbConnection, dbConfig.getUsername());
065    }
066  }
067
068  private void createDatabase(Connection connection) {
069    if (!databaseExists(connection, dbConfig.getDbName())) {
070      createDatabase(connection, dbConfig.getDbName());
071    }
072  }
073
074  private void dropDatabaseIfExists(Connection connection) {
075    if (databaseExists(connection, dbConfig.getDbName())) {
076      dropDatabase(connection, dbConfig.getDbName());
077    }
078  }
079
080  private void dropDatabase(Connection connection, String dbName) {
081    sqlRun(connection, "drop database " + dbName);
082  }
083
084//  private void dropLogin(Connection connection) {
085//    if (loginExists(connection, dbConfig.username)) {
086//      sqlRun(connection, "drop login " + dbConfig.username);
087//    }
088//  }
089
090  private void createDatabase(Connection connection, String dbName) {
091    sqlRun(connection, "create database " + dbName);
092  }
093
094  private void createLogin(Connection connection, String login, String pass) {
095    sqlRun(connection, "create login " + login + " with password = '" + pass + "'");
096  }
097
098  private void createUser(Connection dbConnection, String roleName, String login) {
099    sqlRun(dbConnection, "create user " + roleName + " for login " + login);
100  }
101
102  private void grantOwner(Connection dbConnection, String roleName) {
103    sqlRun(dbConnection, "exec sp_addrolemember 'db_owner', " + roleName);
104  }
105
106  private boolean userExists(Connection dbConnection, String userName) {
107    return sqlHasRow(dbConnection, "select 1 from sys.database_principals where name = '" + userName + "'");
108  }
109
110  private boolean loginExists(Connection connection, String roleName) {
111    return sqlHasRow(connection, "select 1 from master.dbo.syslogins where loginname = '" + roleName + "'");
112  }
113
114  private boolean databaseExists(Connection connection, String dbName) {
115    return sqlHasRow(connection, "select 1 from sys.databases where name='" + dbName + "'");
116  }
117
118  @Override
119  protected ProcessBuilder runProcess() {
120
121    List<String> args = dockerRun();
122    args.add("-e");
123    args.add("ACCEPT_EULA=Y");
124    args.add("-e");
125    args.add("SA_PASSWORD=" + dbConfig.getAdminPassword());
126
127    if (config.isDefaultCollation()) {
128      // do nothing, use server default
129    } else if (config.isExplicitCollation()) {
130      args.add("-e");
131      args.add("MSSQL_COLLATION=" + dbConfig.getCollation());
132    } else {
133      // use case sensitive collation by default
134      args.add("-e");
135      args.add("MSSQL_COLLATION=Latin1_General_100_BIN2");
136    }
137    args.add(config.getImage());
138    return createProcessBuilder(args);
139  }
140
141}