Skip to content

Commit

Permalink
SONAR-7988 fix mssql collation which was badly defined in 5.x
Browse files Browse the repository at this point in the history
  • Loading branch information
Simon Brandhof committed Sep 16, 2016
1 parent 06a5678 commit 6603e70
Show file tree
Hide file tree
Showing 24 changed files with 608 additions and 561 deletions.
Expand Up @@ -23,8 +23,6 @@
import org.sonar.api.platform.ServerUpgradeStatus;
import org.sonar.db.charset.DatabaseCharsetChecker;

import static org.sonar.db.charset.DatabaseCharsetChecker.Flag.ENFORCE_UTF8;

/**
* Checks charset of all existing database columns at startup, before executing db migrations. This requires
* to be defined in platform level 2 ({@link org.sonar.server.platform.platformlevel.PlatformLevel2}).
Expand All @@ -41,19 +39,18 @@ public CheckDatabaseCharsetAtStartup(ServerUpgradeStatus upgradeStatus, Database

@Override
public void start() {
check();
DatabaseCharsetChecker.State state = DatabaseCharsetChecker.State.STARTUP;
if (upgradeStatus.isUpgraded()) {
state = DatabaseCharsetChecker.State.UPGRADE;
} else if (upgradeStatus.isFreshInstall()) {
state = DatabaseCharsetChecker.State.FRESH_INSTALL;
}
charsetChecker.check(state);
}

@Override
public void stop() {
// do nothing
}

protected final void check() {
if (upgradeStatus.isFreshInstall()) {
charsetChecker.check(ENFORCE_UTF8);
} else if (!upgradeStatus.isUpgraded()) {
charsetChecker.check();
}
}
}

This file was deleted.

Expand Up @@ -23,7 +23,6 @@
import org.sonar.server.es.IndexerStartupTask;
import org.sonar.server.issue.filter.RegisterIssueFilters;
import org.sonar.server.platform.ServerLifecycleNotifier;
import org.sonar.server.platform.db.CheckDatabaseCollationDuringMigration;
import org.sonar.server.platform.web.RegisterServletFilters;
import org.sonar.server.qualitygate.RegisterQualityGates;
import org.sonar.server.qualityprofile.RegisterQualityProfiles;
Expand Down Expand Up @@ -53,7 +52,6 @@ protected void configureLevel() {
ServerLifecycleNotifier.class);

addIfStartupLeader(
CheckDatabaseCollationDuringMigration.class,
IndexerStartupTask.class,
RegisterMetrics.class,
RegisterQualityGates.class,
Expand Down
Expand Up @@ -27,34 +27,42 @@
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.sonar.db.charset.DatabaseCharsetChecker.Flag.ENFORCE_UTF8;

public class CheckDatabaseCharsetAtStartupTest {

ServerUpgradeStatus upgradeStatus = mock(ServerUpgradeStatus.class);
DatabaseCharsetChecker charsetChecker = mock(DatabaseCharsetChecker.class);
CheckDatabaseCharsetAtStartup underTest = new CheckDatabaseCharsetAtStartup(upgradeStatus, charsetChecker);
private ServerUpgradeStatus upgradeStatus = mock(ServerUpgradeStatus.class);
private DatabaseCharsetChecker charsetChecker = mock(DatabaseCharsetChecker.class);
private CheckDatabaseCharsetAtStartup underTest = new CheckDatabaseCharsetAtStartup(upgradeStatus, charsetChecker);

@After
public void tearDown() {
underTest.stop();
}

@Test
public void enforce_utf8_if_fresh_install() {
public void test_fresh_install() {
when(upgradeStatus.isFreshInstall()).thenReturn(true);

underTest.start();

verify(charsetChecker).check(ENFORCE_UTF8);
verify(charsetChecker).check(DatabaseCharsetChecker.State.FRESH_INSTALL);
}

@Test
public void do_not_enforce_utf8_and_do_not_repair_at_startup_if_not_fresh_install() {
public void test_upgrade() {
when(upgradeStatus.isUpgraded()).thenReturn(true);

underTest.start();

verify(charsetChecker).check(DatabaseCharsetChecker.State.UPGRADE);
}

@Test
public void test_regular_startup() {
when(upgradeStatus.isFreshInstall()).thenReturn(false);

underTest.start();

verify(charsetChecker).check();
verify(charsetChecker).check(DatabaseCharsetChecker.State.STARTUP);
}
}

This file was deleted.

26 changes: 1 addition & 25 deletions sonar-db/src/main/java/org/sonar/db/charset/CharsetHandler.java
Expand Up @@ -21,9 +21,6 @@

import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import java.util.Set;
import javax.annotation.CheckForNull;

abstract class CharsetHandler {

Expand All @@ -35,31 +32,10 @@ protected CharsetHandler(SqlExecutor selectExecutor) {
this.selectExecutor = selectExecutor;
}

abstract void handle(Connection connection, Set<DatabaseCharsetChecker.Flag> flags) throws SQLException;
abstract void handle(Connection connection, DatabaseCharsetChecker.State state) throws SQLException;

protected SqlExecutor getSqlExecutor() {
return selectExecutor;
}

@CheckForNull
protected final String selectSingleString(Connection connection, String sql) throws SQLException {
String[] cols = selectSingleRow(connection, sql, new SqlExecutor.StringsConverter(1));
return cols == null ? null : cols[0];
}

@CheckForNull
protected final <T> T selectSingleRow(Connection connection, String sql, SqlExecutor.RowConverter<T> rowConverter) throws SQLException {
List<T> rows = select(connection, sql, rowConverter);
if (rows.isEmpty()) {
return null;
}
if (rows.size() == 1) {
return rows.get(0);
}
throw new IllegalStateException("Expecting only one result for [" + sql + "]");
}

protected final <T> List<T> select(Connection connection, String sql, SqlExecutor.RowConverter<T> rowConverter) throws SQLException {
return selectExecutor.executeSelect(connection, sql, rowConverter);
}
}
11 changes: 0 additions & 11 deletions sonar-db/src/main/java/org/sonar/db/charset/ColumnDef.java
Expand Up @@ -19,11 +19,9 @@
*/
package org.sonar.db.charset;

import com.google.common.base.Predicate;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Locale;
import javax.annotation.Nonnull;
import javax.annotation.concurrent.Immutable;
import org.sonar.db.version.DatabaseVersion;

Expand Down Expand Up @@ -97,13 +95,4 @@ public ColumnDef convert(ResultSet rs) throws SQLException {
rs.getString(1), rs.getString(2), rs.getString(3), rs.getString(4), rs.getString(5), rs.getLong(6), nullable);
}
}

public enum IsInSonarQubeTablePredicate implements Predicate<ColumnDef> {
INSTANCE;

@Override
public boolean apply(@Nonnull ColumnDef input) {
return input.isInSonarQubeTable();
}
}
}
Expand Up @@ -31,9 +31,6 @@
import org.sonar.db.dialect.Oracle;
import org.sonar.db.dialect.PostgreSql;

import static com.google.common.collect.Sets.immutableEnumSet;
import static java.util.Arrays.asList;

/**
* On fresh installations, checks that all db columns are UTF8. On all installations on MySQL or MSSQL,
* whatever fresh or upgrade, fixes case-insensitive columns by converting them to
Expand All @@ -43,30 +40,28 @@
*/
public class DatabaseCharsetChecker {

public enum Flag {
ENFORCE_UTF8, AUTO_REPAIR_COLLATION
public enum State {
FRESH_INSTALL, UPGRADE, STARTUP
}

private final Database db;
private final SqlExecutor selectExecutor;
private final SqlExecutor sqlExecutor;

public DatabaseCharsetChecker(Database db) {
this(db, new SqlExecutor());
}

@VisibleForTesting
DatabaseCharsetChecker(Database db, SqlExecutor selectExecutor) {
DatabaseCharsetChecker(Database db, SqlExecutor sqlExecutor) {
this.db = db;
this.selectExecutor = selectExecutor;
this.sqlExecutor = sqlExecutor;
}

public void check(Flag... flags) {
try {
try (Connection connection = db.getDataSource().getConnection()) {
CharsetHandler handler = getHandler(db.getDialect());
if (handler != null) {
handler.handle(connection, immutableEnumSet(asList(flags)));
}
public void check(State state) {
try (Connection connection = db.getDataSource().getConnection()) {
CharsetHandler handler = getHandler(db.getDialect());
if (handler != null) {
handler.handle(connection, state);
}
} catch (SQLException e) {
throw new IllegalStateException(e);
Expand All @@ -81,13 +76,13 @@ CharsetHandler getHandler(Dialect dialect) {
// nothing to check
return null;
case Oracle.ID:
return new OracleCharsetHandler(selectExecutor);
return new OracleCharsetHandler(sqlExecutor);
case PostgreSql.ID:
return new PostgresCharsetHandler(selectExecutor);
return new PostgresCharsetHandler(sqlExecutor, new PostgresMetadataReader(sqlExecutor));
case MySql.ID:
return new MysqlCharsetHandler(selectExecutor);
return new MysqlCharsetHandler(sqlExecutor);
case MsSql.ID:
return new MssqlCharsetHandler(selectExecutor);
return new MssqlCharsetHandler(sqlExecutor, new MssqlMetadataReader(sqlExecutor));
default:
throw new IllegalArgumentException("Database not supported: " + dialect.getId());
}
Expand Down

0 comments on commit 6603e70

Please sign in to comment.