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}