import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
+import java.util.stream.Collectors;
import org.sonar.api.utils.MessageException;
import org.sonar.api.utils.log.Loggers;
+import org.sonar.db.version.SqTables;
import static java.lang.String.format;
import static java.util.Optional.ofNullable;
// Examples:
// issues | key | ''
// projects | name | utf8
- var schema = ofNullable(connection.getSchema()).orElse("public");
+ var sqTables = getSqTables();
+ var schema = getSchema(connection);
List<String[]> rows = getSqlExecutor().select(connection, String.format("select table_name, column_name, collation_name " +
"from information_schema.columns " +
"where table_schema='%s' " +
+ "and table_name in (%s) " +
"and udt_name='varchar' " +
- "order by table_name, column_name", schema), new SqlExecutor.StringsConverter(3 /* columns returned by SELECT */));
+ "order by table_name, column_name", schema, sqTables), new SqlExecutor.StringsConverter(3 /* columns returned by SELECT */));
Set<String> errors = new LinkedHashSet<>();
for (String[] row : rows) {
if (!isBlank(row[2]) && !containsIgnoreCase(row[2], UTF8)) {
}
}
+ private static String getSchema(Connection connection) throws SQLException {
+ return ofNullable(connection.getSchema()).orElse("public");
+ }
+
+ private static String getSqTables() {
+ return SqTables.TABLES.stream().map(s -> "'" + s + "'").collect(Collectors.joining(","));
+ }
+
@VisibleForTesting
PostgresMetadataReader getMetadata() {
return metadata;
import java.sql.Connection;
import java.sql.SQLException;
-import java.util.Arrays;
import java.util.List;
+import java.util.stream.Collectors;
import org.junit.Test;
import org.sonar.api.utils.MessageException;
+import org.sonar.db.version.SqTables;
import static java.util.Arrays.asList;
+import static org.assertj.core.api.Assertions.assertThatCode;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.same;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
private static final String COLUMN_KEE = "kee";
private static final String COLUMN_NAME = "name";
-
- private SqlExecutor sqlExecutor = mock(SqlExecutor.class);
- private Connection connection = mock(Connection.class);
- private PostgresMetadataReader metadata = mock(PostgresMetadataReader.class);
- private PostgresCharsetHandler underTest = new PostgresCharsetHandler(sqlExecutor, metadata);
+ private final SqlExecutor sqlExecutor = mock(SqlExecutor.class);
+ private final Connection connection = mock(Connection.class);
+ private final PostgresMetadataReader metadata = mock(PostgresMetadataReader.class);
+ private final PostgresCharsetHandler underTest = new PostgresCharsetHandler(sqlExecutor, metadata);
@Test
public void fresh_install_verifies_that_default_charset_is_utf8() throws SQLException {
new String[] {TABLE_PROJECTS, COLUMN_NAME, "" /* unset -> uses db collation */}));
// no error
- underTest.handle(connection, DatabaseCharsetChecker.State.UPGRADE);
+ assertThatCode(() -> underTest.handle(connection, DatabaseCharsetChecker.State.UPGRADE))
+ .doesNotThrowAnyException();
+
+ verify(sqlExecutor).select(same(connection), eq("select table_name, column_name,"
+ + " collation_name "
+ + "from information_schema.columns "
+ + "where table_schema='public' "
+ + "and table_name in (" + SqTables.TABLES.stream().map(s -> "'" + s + "'").collect(Collectors.joining(",")) + ") "
+ + "and udt_name='varchar' order by table_name, column_name"), any(SqlExecutor.StringsConverter.class));
+ }
+
+ @Test
+ public void schema_is_taken_into_account_when_selecting_columns() throws Exception {
+ answerDefaultCharset("utf8");
+ answerSchema("test-schema");
+ answerColumns(asList(
+ new String[] {TABLE_ISSUES, COLUMN_KEE, "utf8"},
+ new String[] {TABLE_PROJECTS, COLUMN_NAME, "" /* unset -> uses db collation */}));
+
+ // no error
+ assertThatCode(() -> underTest.handle(connection, DatabaseCharsetChecker.State.UPGRADE))
+ .doesNotThrowAnyException();
+
+ verify(sqlExecutor).select(same(connection), eq("select table_name, column_name,"
+ + " collation_name "
+ + "from information_schema.columns "
+ + "where table_schema='test-schema' "
+ + "and table_name in (" + SqTables.TABLES.stream().map(s -> "'" + s + "'").collect(Collectors.joining(",")) + ") "
+ + "and udt_name='varchar' order by table_name, column_name"), any(SqlExecutor.StringsConverter.class));
}
@Test
public void upgrade_fails_if_default_charset_is_not_utf8() throws Exception {
answerDefaultCharset("latin");
answerColumns(
- Arrays.<String[]>asList(new String[] {TABLE_ISSUES, COLUMN_KEE, "utf8"}));
+ List.<String[]>of(new String[] {TABLE_ISSUES, COLUMN_KEE, "utf8"}));
assertThatThrownBy(() -> underTest.handle(connection, DatabaseCharsetChecker.State.UPGRADE))
.isInstanceOf(MessageException.class)
when(metadata.getDefaultCharset(same(connection))).thenReturn(defaultCollation);
}
+ private void answerSchema(String schema) throws SQLException {
+ when(connection.getSchema()).thenReturn(schema);
+ }
+
private void answerColumns(List<String[]> firstRequest) throws SQLException {
when(sqlExecutor.select(same(connection), anyString(), any(SqlExecutor.StringsConverter.class))).thenReturn(firstRequest);
}