diff options
author | Sébastien Lesaint <sebastien.lesaint@sonarsource.com> | 2016-12-15 10:20:10 +0100 |
---|---|---|
committer | Sébastien Lesaint <sebastien.lesaint@sonarsource.com> | 2016-12-16 14:35:27 +0100 |
commit | 695c9b54d7e7a97075180f17beba537114d404f1 (patch) | |
tree | a1c5e8fc370f09f5d667d521b0754474a2c73a7d /sonar-db | |
parent | afe690ce40c3b178b0e0718ee9ac57c179a481a7 (diff) | |
download | sonarqube-695c9b54d7e7a97075180f17beba537114d404f1.tar.gz sonarqube-695c9b54d7e7a97075180f17beba537114d404f1.zip |
SONAR-8445 move package charset from sonar-db to sonar-db-migration
Diffstat (limited to 'sonar-db')
21 files changed, 0 insertions, 1839 deletions
diff --git a/sonar-db/src/main/java/org/sonar/db/charset/CharsetHandler.java b/sonar-db/src/main/java/org/sonar/db/charset/CharsetHandler.java deleted file mode 100644 index de27d9925e0..00000000000 --- a/sonar-db/src/main/java/org/sonar/db/charset/CharsetHandler.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.db.charset; - -import java.sql.Connection; -import java.sql.SQLException; - -abstract class CharsetHandler { - - protected static final String UTF8 = "utf8"; - - private final SqlExecutor selectExecutor; - - protected CharsetHandler(SqlExecutor selectExecutor) { - this.selectExecutor = selectExecutor; - } - - abstract void handle(Connection connection, DatabaseCharsetChecker.State state) throws SQLException; - - protected SqlExecutor getSqlExecutor() { - return selectExecutor; - } - -} diff --git a/sonar-db/src/main/java/org/sonar/db/charset/ColumnDef.java b/sonar-db/src/main/java/org/sonar/db/charset/ColumnDef.java deleted file mode 100644 index c2c20f176bf..00000000000 --- a/sonar-db/src/main/java/org/sonar/db/charset/ColumnDef.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.db.charset; - -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.Locale; -import javax.annotation.concurrent.Immutable; -import org.sonar.db.version.DatabaseVersion; - -/** - * Result of standard SQL command "select * from INFORMATION_SCHEMA" (columns listed in {@link #SELECT_COLUMNS}). - */ -@Immutable -public class ColumnDef { - - public static final String SELECT_COLUMNS = "select table_name, column_name, character_set_name, collation_name, data_type, character_maximum_length, is_nullable "; - - private final String table; - private final String column; - private final String charset; - private final String collation; - private final String dataType; - private final long size; - private final boolean nullable; - - public ColumnDef(String table, String column, String charset, String collation, String dataType, long size, boolean nullable) { - this.table = table; - this.column = column; - this.charset = charset; - this.collation = collation; - this.dataType = dataType; - this.size = size; - this.nullable = nullable; - } - - public String getTable() { - return table; - } - - public String getColumn() { - return column; - } - - public String getCharset() { - return charset; - } - - public String getCollation() { - return collation; - } - - public String getDataType() { - return dataType; - } - - public long getSize() { - return size; - } - - public boolean isNullable() { - return nullable; - } - - public boolean isInSonarQubeTable() { - String tableName = table.toLowerCase(Locale.ENGLISH); - return DatabaseVersion.TABLES.contains(tableName) || DatabaseVersion.OLD_DROPPED_TABLES.contains(tableName); - } - - public enum ColumnDefRowConverter implements SqlExecutor.RowConverter<ColumnDef> { - INSTANCE; - - @Override - public ColumnDef convert(ResultSet rs) throws SQLException { - String nullableText = rs.getString(7); - boolean nullable = "YES".equalsIgnoreCase(nullableText); - - return new ColumnDef( - rs.getString(1), rs.getString(2), rs.getString(3), rs.getString(4), rs.getString(5), rs.getLong(6), nullable); - } - } -} diff --git a/sonar-db/src/main/java/org/sonar/db/charset/DatabaseCharsetChecker.java b/sonar-db/src/main/java/org/sonar/db/charset/DatabaseCharsetChecker.java deleted file mode 100644 index 5a91685dc2e..00000000000 --- a/sonar-db/src/main/java/org/sonar/db/charset/DatabaseCharsetChecker.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.db.charset; - -import com.google.common.annotations.VisibleForTesting; -import java.sql.Connection; -import java.sql.SQLException; -import javax.annotation.CheckForNull; -import org.sonar.db.Database; -import org.sonar.db.dialect.Dialect; -import org.sonar.db.dialect.H2; -import org.sonar.db.dialect.MsSql; -import org.sonar.db.dialect.MySql; -import org.sonar.db.dialect.Oracle; -import org.sonar.db.dialect.PostgreSql; - -/** - * 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 - * case-sensitive. - * - * See SONAR-6171 and SONAR-7549 - */ -public class DatabaseCharsetChecker { - - public enum State { - FRESH_INSTALL, UPGRADE, STARTUP - } - - private final Database db; - private final SqlExecutor sqlExecutor; - - public DatabaseCharsetChecker(Database db) { - this(db, new SqlExecutor()); - } - - @VisibleForTesting - DatabaseCharsetChecker(Database db, SqlExecutor sqlExecutor) { - this.db = db; - this.sqlExecutor = sqlExecutor; - } - - 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); - } - } - - @VisibleForTesting - @CheckForNull - CharsetHandler getHandler(Dialect dialect) { - switch (dialect.getId()) { - case H2.ID: - // nothing to check - return null; - case Oracle.ID: - return new OracleCharsetHandler(sqlExecutor); - case PostgreSql.ID: - return new PostgresCharsetHandler(sqlExecutor, new PostgresMetadataReader(sqlExecutor)); - case MySql.ID: - return new MysqlCharsetHandler(sqlExecutor); - case MsSql.ID: - return new MssqlCharsetHandler(sqlExecutor, new MssqlMetadataReader(sqlExecutor)); - default: - throw new IllegalArgumentException("Database not supported: " + dialect.getId()); - } - } -} diff --git a/sonar-db/src/main/java/org/sonar/db/charset/MssqlCharsetHandler.java b/sonar-db/src/main/java/org/sonar/db/charset/MssqlCharsetHandler.java deleted file mode 100644 index 818714966dc..00000000000 --- a/sonar-db/src/main/java/org/sonar/db/charset/MssqlCharsetHandler.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.db.charset; - -import com.google.common.annotations.VisibleForTesting; -import java.sql.Connection; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.List; -import java.util.stream.Collectors; -import org.sonar.api.utils.MessageException; -import org.sonar.api.utils.log.Logger; -import org.sonar.api.utils.log.Loggers; - -import static java.lang.String.format; -import static org.apache.commons.lang.StringUtils.containsIgnoreCase; - -class MssqlCharsetHandler extends CharsetHandler { - - private static final Logger LOGGER = Loggers.get(MssqlCharsetHandler.class); - private static final String CASE_SENSITIVE_ACCENT_SENSITIVE = "_CS_AS"; - private static final String CASE_INSENSITIVE_ACCENT_INSENSITIVE = "_CI_AI"; - private static final String CASE_INSENSITIVE_ACCENT_SENSITIVE = "_CI_AS"; - private static final String CASE_SENSITIVE_ACCENT_INSENSITIVE = "_CS_AI"; - private static final String BIN = "BIN"; - private static final String BIN2 = "BIN2"; - - private final MssqlMetadataReader metadata; - - MssqlCharsetHandler(SqlExecutor selectExecutor, MssqlMetadataReader metadataReader) { - super(selectExecutor); - this.metadata = metadataReader; - } - - @Override - void handle(Connection connection, DatabaseCharsetChecker.State state) throws SQLException { - expectCaseSensitiveDefaultCollation(connection); - if (state == DatabaseCharsetChecker.State.UPGRADE || state == DatabaseCharsetChecker.State.STARTUP) { - repairColumns(connection); - } - } - - private void expectCaseSensitiveDefaultCollation(Connection connection) throws SQLException { - LOGGER.info("Verify that database collation is case-sensitive and accent-sensitive"); - String defaultCollation = metadata.getDefaultCollation(connection); - - if (!isCollationCorrect(defaultCollation)) { - String fixedCollation = toCaseSensitive(defaultCollation); - throw MessageException.of(format( - "Database collation must be case-sensitive and accent-sensitive. It is %s but should be %s.", defaultCollation, fixedCollation)); - } - } - - private void repairColumns(Connection connection) throws SQLException { - String defaultCollation = metadata.getDefaultCollation(connection); - - // All VARCHAR columns are returned. No need to check database general collation. - // Example of row: - // issues | kee | Latin1_General_CS_AS or Latin1_General_100_CI_AS_KS_WS - List<ColumnDef> columns = metadata.getColumnDefs(connection); - for (ColumnDef column : columns.stream().filter(ColumnDef::isInSonarQubeTable).collect(Collectors.toList())) { - String collation = column.getCollation(); - if (!isCollationCorrect(collation)) { - repairColumnCollation(connection, column, toCaseSensitive(collation)); - } else if ("Latin1_General_CS_AS".equals(collation) && !collation.equals(defaultCollation)) { - repairColumnCollation(connection, column, defaultCollation); - } - } - } - - /** - * Collation is correct if contains {@link #CASE_SENSITIVE_ACCENT_SENSITIVE} or {@link #BIN} or {@link #BIN2}. - */ - private static boolean isCollationCorrect(String collation) { - return containsIgnoreCase(collation, CASE_SENSITIVE_ACCENT_SENSITIVE) - || containsIgnoreCase(collation, BIN) - || containsIgnoreCase(collation, BIN2); - } - - private void repairColumnCollation(Connection connection, ColumnDef column, String expectedCollation) throws SQLException { - // 1. select the indices defined on this column - List<ColumnIndex> indices = metadata.getColumnIndices(connection, column); - - // 2. drop indices - for (ColumnIndex index : indices) { - getSqlExecutor().executeDdl(connection, format("DROP INDEX %s.%s", column.getTable(), index.name)); - } - - // 3. alter collation of column - String nullability = column.isNullable() ? "NULL" : "NOT NULL"; - String size = column.getSize() >= 0 ? String.valueOf(column.getSize()) : "max"; - String alterSql = format("ALTER TABLE %s ALTER COLUMN %s %s(%s) COLLATE %s %s", - column.getTable(), column.getColumn(), column.getDataType(), size, expectedCollation, nullability); - LOGGER.info("Changing collation of column [{}.{}] from {} to {} | sql=", column.getTable(), column.getColumn(), column.getCollation(), expectedCollation, alterSql); - getSqlExecutor().executeDdl(connection, alterSql); - - // 4. re-create indices - for (ColumnIndex index : indices) { - String uniqueSql = index.unique ? "UNIQUE" : ""; - String createIndexSql = format("CREATE %s INDEX %s ON %s (%s)", uniqueSql, index.name, column.getTable(), index.csvColumns); - getSqlExecutor().executeDdl(connection, createIndexSql); - } - } - - @VisibleForTesting - static String toCaseSensitive(String collation) { - // Example: Latin1_General_CI_AI --> Latin1_General_CS_AS or Latin1_General_100_CI_AS_KS_WS --> Latin1_General_100_CS_AS_KS_WS - return collation - .replace(CASE_INSENSITIVE_ACCENT_INSENSITIVE, CASE_SENSITIVE_ACCENT_SENSITIVE) - .replace(CASE_INSENSITIVE_ACCENT_SENSITIVE, CASE_SENSITIVE_ACCENT_SENSITIVE) - .replace(CASE_SENSITIVE_ACCENT_INSENSITIVE, CASE_SENSITIVE_ACCENT_SENSITIVE); - } - - @VisibleForTesting - static class ColumnIndex { - private final String name; - private final boolean unique; - private final String csvColumns; - - public ColumnIndex(String name, boolean unique, String csvColumns) { - this.name = name; - this.unique = unique; - this.csvColumns = csvColumns; - } - } - - @VisibleForTesting - enum ColumnIndexConverter implements SqlExecutor.RowConverter<ColumnIndex> { - INSTANCE; - @Override - public ColumnIndex convert(ResultSet rs) throws SQLException { - return new ColumnIndex(rs.getString(1), rs.getBoolean(2), rs.getString(3)); - } - } - -} diff --git a/sonar-db/src/main/java/org/sonar/db/charset/MssqlMetadataReader.java b/sonar-db/src/main/java/org/sonar/db/charset/MssqlMetadataReader.java deleted file mode 100644 index 0f7aa18afe7..00000000000 --- a/sonar-db/src/main/java/org/sonar/db/charset/MssqlMetadataReader.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.db.charset; - -import java.sql.Connection; -import java.sql.SQLException; -import java.util.List; - -import static java.lang.String.format; - -public class MssqlMetadataReader { - private final SqlExecutor sqlExecutor; - - public MssqlMetadataReader(SqlExecutor sqlExecutor) { - this.sqlExecutor = sqlExecutor; - } - - public String getDefaultCollation(Connection connection) throws SQLException { - return sqlExecutor.selectSingleString(connection, "SELECT CONVERT(VARCHAR, DATABASEPROPERTYEX(DB_NAME(), 'Collation'))"); - } - - public List<ColumnDef> getColumnDefs(Connection connection) throws SQLException { - return sqlExecutor.select(connection, - ColumnDef.SELECT_COLUMNS + - "FROM [INFORMATION_SCHEMA].[COLUMNS] " + - "WHERE collation_name is not null " + - "ORDER BY table_name,column_name", - ColumnDef.ColumnDefRowConverter.INSTANCE); - } - - public List<MssqlCharsetHandler.ColumnIndex> getColumnIndices(Connection connection, ColumnDef column) throws SQLException { - String selectIndicesSql = format("SELECT I.name as index_name, I.is_unique as unik, IndexedColumns " + - " FROM sys.indexes I " + - " JOIN sys.tables T ON T.Object_id = I.Object_id " + - " JOIN (SELECT * FROM ( " + - " SELECT IC2.object_id, IC2.index_id, " + - " STUFF((SELECT ' ,' + C.name " + - " FROM sys.index_columns IC1 " + - " JOIN sys.columns C " + - " ON C.object_id = IC1.object_id " + - " AND C.column_id = IC1.column_id " + - " AND IC1.is_included_column = 0 " + - " WHERE IC1.object_id = IC2.object_id " + - " AND IC1.index_id = IC2.index_id " + - " GROUP BY IC1.object_id,C.name,index_id " + - " ORDER BY MAX(IC1.key_ordinal) " + - " FOR XML PATH('')), 1, 2, '') IndexedColumns " + - " FROM sys.index_columns IC2 " + - " GROUP BY IC2.object_id ,IC2.index_id) tmp1 )tmp2 " + - " ON I.object_id = tmp2.object_id AND I.Index_id = tmp2.index_id " + - " WHERE I.is_primary_key = 0 AND I.is_unique_constraint = 0 " + - " and T.name =('%s') " + - " and CHARINDEX ('%s',IndexedColumns)>0", column.getTable(), column.getColumn()); - return sqlExecutor.select(connection, selectIndicesSql, MssqlCharsetHandler.ColumnIndexConverter.INSTANCE); - } -} diff --git a/sonar-db/src/main/java/org/sonar/db/charset/MysqlCharsetHandler.java b/sonar-db/src/main/java/org/sonar/db/charset/MysqlCharsetHandler.java deleted file mode 100644 index 2190e6a3bb1..00000000000 --- a/sonar-db/src/main/java/org/sonar/db/charset/MysqlCharsetHandler.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.db.charset; - -import java.sql.Connection; -import java.sql.SQLException; -import java.util.List; -import java.util.stream.Collectors; -import org.apache.commons.lang.StringUtils; -import org.sonar.api.utils.log.Logger; -import org.sonar.api.utils.log.Loggers; - -import static java.lang.String.format; -import static org.apache.commons.lang.StringUtils.endsWithIgnoreCase; - -class MysqlCharsetHandler extends CharsetHandler { - - private static final Logger LOGGER = Loggers.get(MysqlCharsetHandler.class); - private static final String TYPE_LONGTEXT = "longtext"; - - MysqlCharsetHandler(SqlExecutor selectExecutor) { - super(selectExecutor); - } - - @Override - void handle(Connection connection, DatabaseCharsetChecker.State state) throws SQLException { - // all the VARCHAR columns have always been created with UTF8 charset on mysql - // (since SonarQube 2.12 to be precise). The default charset does not require - // to be UTF8. It is not used. No need to verify it. - // Still if a column has been accidentally created with a case-insensitive collation, - // then we can repair it by moving to the same case-sensitive collation. That should - // never occur. - if (state == DatabaseCharsetChecker.State.UPGRADE) { - repairCaseInsensitiveColumns(connection); - } - } - - private void repairCaseInsensitiveColumns(Connection connection) throws SQLException { - // All VARCHAR columns are returned. No need to check database general collation. - // Example of row: - // issues | kee | utf8 | utf8_bin - List<ColumnDef> columns = getSqlExecutor().select(connection, - ColumnDef.SELECT_COLUMNS + - "FROM INFORMATION_SCHEMA.columns " + - "WHERE table_schema=database() and character_set_name is not null and collation_name is not null", - ColumnDef.ColumnDefRowConverter.INSTANCE); - - List<ColumnDef> invalidColumns = columns.stream() - .filter(ColumnDef::isInSonarQubeTable) - .filter(column -> endsWithIgnoreCase(column.getCollation(), "_ci")) - .collect(Collectors.toList()); - for (ColumnDef column : invalidColumns) { - repairCaseInsensitiveColumn(connection, column); - } - } - - private void repairCaseInsensitiveColumn(Connection connection, ColumnDef column) - throws SQLException { - String csCollation = toCaseSensitive(column.getCollation()); - - String nullability = column.isNullable() ? "NULL" : "NOT NULL"; - String type = column.getDataType().equalsIgnoreCase(TYPE_LONGTEXT) ? TYPE_LONGTEXT : format("%s(%d)", column.getDataType(), column.getSize()); - String alterSql = format("ALTER TABLE %s MODIFY %s %s CHARACTER SET '%s' COLLATE '%s' %s", - column.getTable(), column.getColumn(), type, column.getCharset(), csCollation, nullability); - LOGGER.info("Changing collation of column [{}.{}] from {} to {} | sql={}", column.getTable(), column.getColumn(), column.getCollation(), csCollation, alterSql); - getSqlExecutor().executeDdl(connection, alterSql); - } - - private static String toCaseSensitive(String caseInsensitiveCollation) { - // Example: big5_chinese_ci becomes big5_bin - // Full list of collations is available with SQL request "show collation" - return StringUtils.substringBefore(caseInsensitiveCollation, "_") + "_bin"; - } -} diff --git a/sonar-db/src/main/java/org/sonar/db/charset/OracleCharsetHandler.java b/sonar-db/src/main/java/org/sonar/db/charset/OracleCharsetHandler.java deleted file mode 100644 index 09f855958e6..00000000000 --- a/sonar-db/src/main/java/org/sonar/db/charset/OracleCharsetHandler.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.db.charset; - -import java.sql.Connection; -import java.sql.SQLException; -import org.sonar.api.utils.MessageException; -import org.sonar.api.utils.log.Loggers; - -import static java.lang.String.format; -import static org.apache.commons.lang.StringUtils.containsIgnoreCase; - -class OracleCharsetHandler extends CharsetHandler { - - OracleCharsetHandler(SqlExecutor selectExecutor) { - super(selectExecutor); - } - - @Override - public void handle(Connection connection, DatabaseCharsetChecker.State state) throws SQLException { - // Charset is a global setting on Oracle, it can't be set on a specified schema with a - // different value. To not block users who already have a SonarQube schema, charset - // is verified only on fresh installs but not on upgrades. Let's hope they won't face - // any errors related to charset if they didn't follow the UTF8 requirement when creating - // the schema in previous SonarQube versions. - if (state == DatabaseCharsetChecker.State.FRESH_INSTALL) { - Loggers.get(getClass()).info("Verify that database charset is UTF8"); - expectUtf8(connection); - } - } - - private void expectUtf8(Connection connection) throws SQLException { - // Oracle does not allow to override character set on tables. Only global charset is verified. - String charset = getSqlExecutor().selectSingleString(connection, "select value from nls_database_parameters where parameter='NLS_CHARACTERSET'"); - String sort = getSqlExecutor().selectSingleString(connection, "select value from nls_database_parameters where parameter='NLS_SORT'"); - if (!containsIgnoreCase(charset, UTF8) || !"BINARY".equalsIgnoreCase(sort)) { - throw MessageException.of(format("Oracle must be have UTF8 charset and BINARY sort. NLS_CHARACTERSET is %s and NLS_SORT is %s.", charset, sort)); - } - } -} diff --git a/sonar-db/src/main/java/org/sonar/db/charset/PostgresCharsetHandler.java b/sonar-db/src/main/java/org/sonar/db/charset/PostgresCharsetHandler.java deleted file mode 100644 index 69539cfb74e..00000000000 --- a/sonar-db/src/main/java/org/sonar/db/charset/PostgresCharsetHandler.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.db.charset; - -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Joiner; -import java.sql.Connection; -import java.sql.SQLException; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; -import org.sonar.api.utils.MessageException; -import org.sonar.api.utils.log.Loggers; - -import static java.lang.String.format; -import static org.apache.commons.lang.StringUtils.containsIgnoreCase; -import static org.apache.commons.lang.StringUtils.isBlank; - -class PostgresCharsetHandler extends CharsetHandler { - - private final PostgresMetadataReader metadata; - - PostgresCharsetHandler(SqlExecutor selectExecutor, PostgresMetadataReader metadata) { - super(selectExecutor); - this.metadata = metadata; - } - - @Override - void handle(Connection connection, DatabaseCharsetChecker.State state) throws SQLException { - // PostgreSQL does not have concept of case-sensitive collation. Only charset ("encoding" in postgresql terminology) - // must be verified. - expectUtf8AsDefault(connection); - - if (state == DatabaseCharsetChecker.State.UPGRADE || state == DatabaseCharsetChecker.State.STARTUP) { - // no need to check columns on fresh installs... as they are not supposed to exist! - expectUtf8Columns(connection); - } - } - - private void expectUtf8AsDefault(Connection connection) throws SQLException { - Loggers.get(getClass()).info("Verify that database charset supports UTF8"); - String collation = metadata.getDefaultCharset(connection); - if (!containsIgnoreCase(collation, UTF8)) { - throw MessageException.of(format("Database charset is %s. It must support UTF8.", collation)); - } - } - - private void expectUtf8Columns(Connection connection) throws SQLException { - // Charset is defined globally and can be overridden on each column. - // This request returns all VARCHAR columns. Charset may be empty. - // Examples: - // issues | key | '' - // projects | name | utf8 - List<String[]> rows = getSqlExecutor().select(connection, "select table_name, column_name, collation_name " + - "from information_schema.columns " + - "where table_schema='public' " + - "and udt_name='varchar' " + - "order by table_name, column_name", 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)) { - errors.add(format("%s.%s", row[0], row[1])); - } - } - - if (!errors.isEmpty()) { - throw MessageException.of(format("Database columns [%s] must have UTF8 charset.", Joiner.on(", ").join(errors))); - } - } - - @VisibleForTesting - PostgresMetadataReader getMetadata() { - return metadata; - } - -} diff --git a/sonar-db/src/main/java/org/sonar/db/charset/PostgresMetadataReader.java b/sonar-db/src/main/java/org/sonar/db/charset/PostgresMetadataReader.java deleted file mode 100644 index eecca8d1c01..00000000000 --- a/sonar-db/src/main/java/org/sonar/db/charset/PostgresMetadataReader.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.db.charset; - -import java.sql.Connection; -import java.sql.SQLException; - -public class PostgresMetadataReader { - - private final SqlExecutor sqlExecutor; - - public PostgresMetadataReader(SqlExecutor sqlExecutor) { - this.sqlExecutor = sqlExecutor; - } - - public String getDefaultCharset(Connection connection) throws SQLException { - return sqlExecutor.selectSingleString(connection, "select pg_encoding_to_char(encoding) from pg_database where datname = current_database()"); - } -} diff --git a/sonar-db/src/main/java/org/sonar/db/charset/SqlExecutor.java b/sonar-db/src/main/java/org/sonar/db/charset/SqlExecutor.java deleted file mode 100644 index f9e56cd7596..00000000000 --- a/sonar-db/src/main/java/org/sonar/db/charset/SqlExecutor.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.db.charset; - -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.ArrayList; -import java.util.List; -import javax.annotation.CheckForNull; -import org.sonar.db.DatabaseUtils; - -public class SqlExecutor { - - public <T> List<T> select(Connection connection, String sql, RowConverter<T> rowConverter) throws SQLException { - PreparedStatement stmt = null; - ResultSet rs = null; - try { - stmt = connection.prepareStatement(sql); - rs = stmt.executeQuery(); - List<T> result = new ArrayList<>(); - while (rs.next()) { - result.add(rowConverter.convert(rs)); - } - return result; - - } finally { - DatabaseUtils.closeQuietly(rs); - DatabaseUtils.closeQuietly(stmt); - } - } - - public void executeDdl(Connection connection, String sql) throws SQLException { - try (Statement stmt = connection.createStatement()) { - stmt.execute(sql); - } - } - - @CheckForNull - public 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 - public 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 + "]"); - } - - @FunctionalInterface - public interface RowConverter<T> { - T convert(ResultSet rs) throws SQLException; - } - - public static class StringsConverter implements RowConverter<String[]> { - private final int nbColumns; - - public StringsConverter(int nbColumns) { - this.nbColumns = nbColumns; - } - - @Override - public String[] convert(ResultSet rs) throws SQLException { - String[] row = new String[nbColumns]; - for (int i = 0; i < nbColumns; i++) { - row[i] = DatabaseUtils.getString(rs, i + 1); - } - return row; - } - } -} diff --git a/sonar-db/src/main/java/org/sonar/db/charset/package-info.java b/sonar-db/src/main/java/org/sonar/db/charset/package-info.java deleted file mode 100644 index 25a4faf160e..00000000000 --- a/sonar-db/src/main/java/org/sonar/db/charset/package-info.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -@ParametersAreNonnullByDefault -package org.sonar.db.charset; - -import javax.annotation.ParametersAreNonnullByDefault; - diff --git a/sonar-db/src/test/java/org/sonar/db/charset/ColumnDefTest.java b/sonar-db/src/test/java/org/sonar/db/charset/ColumnDefTest.java deleted file mode 100644 index 55b02e0ea1e..00000000000 --- a/sonar-db/src/test/java/org/sonar/db/charset/ColumnDefTest.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.db.charset; - -import org.junit.Test; - -import static org.assertj.core.api.Assertions.assertThat; - -public class ColumnDefTest { - - @Test - public void isInSonarQubeTable_returns_false_if_sqlazure_system_table() { - ColumnDef underTest = new ColumnDef("sys.sysusers", "login", "charset", "collation", "NVARCHAR", 100L, false); - assertThat(underTest.isInSonarQubeTable()).isFalse(); - - underTest = new ColumnDef("SYS.SYSUSERS", "login", "charset", "collation", "NVARCHAR", 100L, false); - assertThat(underTest.isInSonarQubeTable()).isFalse(); - } - - @Test - public void isInSonarQubeTable_returns_true_if_table_created_by_sonarqube() { - ColumnDef underTest = new ColumnDef("project_measures", "text_value", "charset", "collation", "NVARCHAR", 100L, false); - assertThat(underTest.isInSonarQubeTable()).isTrue(); - - underTest = new ColumnDef("PROJECT_MEASURES", "text_value", "charset", "collation", "NVARCHAR", 100L, false); - assertThat(underTest.isInSonarQubeTable()).isTrue(); - } - - @Test - public void isInSonarQubeTable_returns_true_if_table_existed_in_previous_versions_of_sonarqube() { - ColumnDef underTest = new ColumnDef("activities", "kee", "charset", "collation", "NVARCHAR", 100L, false); - assertThat(underTest.isInSonarQubeTable()).isTrue(); - } -} diff --git a/sonar-db/src/test/java/org/sonar/db/charset/DatabaseCharsetCheckerTest.java b/sonar-db/src/test/java/org/sonar/db/charset/DatabaseCharsetCheckerTest.java deleted file mode 100644 index d707ff9ee0b..00000000000 --- a/sonar-db/src/test/java/org/sonar/db/charset/DatabaseCharsetCheckerTest.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.db.charset; - -import java.sql.Connection; -import java.sql.SQLException; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.mockito.Mockito; -import org.sonar.db.Database; -import org.sonar.db.dialect.Dialect; -import org.sonar.db.dialect.H2; -import org.sonar.db.dialect.MsSql; -import org.sonar.db.dialect.MySql; -import org.sonar.db.dialect.Oracle; -import org.sonar.db.dialect.PostgreSql; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -public class DatabaseCharsetCheckerTest { - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - private Database db = mock(Database.class, Mockito.RETURNS_MOCKS); - private CharsetHandler handler = mock(CharsetHandler.class); - private DatabaseCharsetChecker underTest = spy(new DatabaseCharsetChecker(db)); - - @Test - public void executes_handler() throws Exception { - Oracle dialect = new Oracle(); - when(underTest.getHandler(dialect)).thenReturn(handler); - when(db.getDialect()).thenReturn(dialect); - - underTest.check(DatabaseCharsetChecker.State.UPGRADE); - verify(handler).handle(any(Connection.class), eq(DatabaseCharsetChecker.State.UPGRADE)); - } - - @Test - public void throws_ISE_if_handler_fails() throws Exception { - Oracle dialect = new Oracle(); - when(underTest.getHandler(dialect)).thenReturn(handler); - when(db.getDialect()).thenReturn(dialect); - doThrow(new SQLException("failure")).when(handler).handle(any(Connection.class), any(DatabaseCharsetChecker.State.class)); - - expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("failure"); - underTest.check(DatabaseCharsetChecker.State.UPGRADE); - } - - @Test - public void does_nothing_if_h2() throws Exception { - assertThat(underTest.getHandler(new H2())).isNull(); - } - - @Test - public void getHandler_returns_MysqlCharsetHandler_if_mysql() throws Exception { - assertThat(underTest.getHandler(new MySql())).isInstanceOf(MysqlCharsetHandler.class); - } - - @Test - public void getHandler_returns_MssqlCharsetHandler_if_mssql() throws Exception { - assertThat(underTest.getHandler(new MsSql())).isInstanceOf(MssqlCharsetHandler.class); - } - - @Test - public void getHandler_returns_OracleCharsetHandler_if_oracle() throws Exception { - assertThat(underTest.getHandler(new Oracle())).isInstanceOf(OracleCharsetHandler.class); - } - - @Test - public void getHandler_returns_PostgresCharsetHandler_if_postgres() throws Exception { - assertThat(underTest.getHandler(new PostgreSql())).isInstanceOf(PostgresCharsetHandler.class); - } - - @Test - public void getHandler_throws_IAE_if_unsupported_db() throws Exception { - Dialect unsupportedDialect = mock(Dialect.class); - when(unsupportedDialect.getId()).thenReturn("foo"); - - expectedException.expect(IllegalArgumentException.class); - expectedException.expectMessage("Database not supported: foo"); - underTest.getHandler(unsupportedDialect); - } -} diff --git a/sonar-db/src/test/java/org/sonar/db/charset/MssqlCharsetHandlerTest.java b/sonar-db/src/test/java/org/sonar/db/charset/MssqlCharsetHandlerTest.java deleted file mode 100644 index 13e9dd78c7e..00000000000 --- a/sonar-db/src/test/java/org/sonar/db/charset/MssqlCharsetHandlerTest.java +++ /dev/null @@ -1,240 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.db.charset; - -import com.tngtech.java.junit.dataprovider.DataProvider; -import com.tngtech.java.junit.dataprovider.DataProviderRunner; -import com.tngtech.java.junit.dataprovider.UseDataProvider; -import java.sql.Connection; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Stream; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.junit.runner.RunWith; -import org.sonar.api.utils.MessageException; - -import static java.lang.String.format; -import static java.util.Arrays.asList; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.same; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -@RunWith(DataProviderRunner.class) -public class MssqlCharsetHandlerTest { - - private static final String TABLE_ISSUES = "issues"; - private static final String TABLE_PROJECTS = "projects"; - private static final String COLUMN_KEE = "kee"; - private static final String COLUMN_NAME = "name"; - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - private SqlExecutor sqlExecutor = mock(SqlExecutor.class); - private MssqlMetadataReader metadata = mock(MssqlMetadataReader.class); - private MssqlCharsetHandler underTest = new MssqlCharsetHandler(sqlExecutor, metadata); - private Connection connection = mock(Connection.class); - - @Test - public void fresh_install_verifies_that_default_collation_is_CS_AS() throws SQLException { - answerDefaultCollation("Latin1_General_CS_AS"); - - underTest.handle(connection, DatabaseCharsetChecker.State.FRESH_INSTALL); - - verify(metadata).getDefaultCollation(connection); - } - - @Test - public void fresh_install_fails_if_default_collation_is_not_CS_AS() throws SQLException { - answerDefaultCollation("Latin1_General_CI_AI"); - - expectedException.expect(MessageException.class); - expectedException.expectMessage("Database collation must be case-sensitive and accent-sensitive. It is Latin1_General_CI_AI but should be Latin1_General_CS_AS."); - underTest.handle(connection, DatabaseCharsetChecker.State.FRESH_INSTALL); - } - - @Test - public void upgrade_fails_if_default_collation_is_not_CS_AS() throws SQLException { - answerDefaultCollation("Latin1_General_CI_AI"); - - expectedException.expect(MessageException.class); - expectedException.expectMessage("Database collation must be case-sensitive and accent-sensitive. It is Latin1_General_CI_AI but should be Latin1_General_CS_AS."); - underTest.handle(connection, DatabaseCharsetChecker.State.UPGRADE); - } - - @Test - public void upgrade_checks_that_columns_are_CS_AS() throws SQLException { - answerDefaultCollation("Latin1_General_CS_AS"); - answerColumnDefs( - new ColumnDef(TABLE_ISSUES, COLUMN_KEE, "Latin1_General", "Latin1_General_CS_AS", "varchar", 10, false), - new ColumnDef(TABLE_PROJECTS, COLUMN_NAME, "Latin1_General", "Latin1_General_CS_AS", "varchar", 10, false)); - - // do not fail - underTest.handle(connection, DatabaseCharsetChecker.State.UPGRADE); - } - - @Test - public void upgrade_repairs_CI_AI_columns() throws SQLException { - answerDefaultCollation("Latin1_General_CS_AS"); - answerColumnDefs( - new ColumnDef(TABLE_ISSUES, COLUMN_KEE, "Latin1_General", "Latin1_General_CS_AS", "varchar", 10, false), - new ColumnDef(TABLE_PROJECTS, COLUMN_NAME, "Latin1_General", "Latin1_General_CI_AI", "varchar", 10, false)); - - underTest.handle(connection, DatabaseCharsetChecker.State.UPGRADE); - - verify(sqlExecutor).executeDdl(connection, "ALTER TABLE projects ALTER COLUMN name varchar(10) COLLATE Latin1_General_CS_AS NOT NULL"); - } - - @Test - public void upgrade_repairs_indexed_CI_AI_columns() throws SQLException { - answerDefaultCollation("Latin1_General_CS_AS"); - answerColumnDefs( - new ColumnDef(TABLE_ISSUES, COLUMN_KEE, "Latin1_General", "Latin1_General_CS_AS", "varchar", 10, false), - new ColumnDef(TABLE_PROJECTS, COLUMN_NAME, "Latin1_General", "Latin1_General_CI_AI", "varchar", 10, false)); - answerIndices( - new MssqlCharsetHandler.ColumnIndex("projects_name", false, "name"), - // This index is on two columns. Note that it does not make sense for table "projects" ! - new MssqlCharsetHandler.ColumnIndex("projects_login_and_name", true, "login,name")); - - underTest.handle(connection, DatabaseCharsetChecker.State.UPGRADE); - - verify(sqlExecutor).executeDdl(connection, "DROP INDEX projects.projects_name"); - verify(sqlExecutor).executeDdl(connection, "DROP INDEX projects.projects_login_and_name"); - verify(sqlExecutor).executeDdl(connection, "ALTER TABLE projects ALTER COLUMN name varchar(10) COLLATE Latin1_General_CS_AS NOT NULL"); - verify(sqlExecutor).executeDdl(connection, "CREATE INDEX projects_name ON projects (name)"); - verify(sqlExecutor).executeDdl(connection, "CREATE UNIQUE INDEX projects_login_and_name ON projects (login,name)"); - } - - @Test - @UseDataProvider("combinationsOfCsAsAndSuffix") - public void repair_case_insensitive_accent_insensitive_combinations_with_or_without_suffix(String collation, String expectedCollation) - throws Exception { - answerDefaultCollation("Latin1_General_CS_AS"); - answerColumnDefs(new ColumnDef(TABLE_ISSUES, COLUMN_KEE, "Latin1_General", collation, "varchar", 10, false)); - - underTest.handle(connection, DatabaseCharsetChecker.State.UPGRADE); - - verify(sqlExecutor).executeDdl(connection, "ALTER TABLE issues ALTER COLUMN kee varchar(10) COLLATE " + expectedCollation + " NOT NULL"); - } - - @DataProvider - public static Object[][] combinationsOfCsAsAndSuffix() { - List<String[]> res = new ArrayList<>(); - for (String sensitivity : asList("CI_AI", "CI_AS", "CS_AI")) { - for (String suffix : asList("", "_KS_WS")) { - res.add(new String[] { - format("Latin1_General_%s%s", sensitivity, suffix), - format("Latin1_General_CS_AS%s", suffix) - }); - } - } - return res.stream().toArray(Object[][]::new); - } - - @Test - public void support_the_max_size_of_varchar_column() throws Exception { - answerDefaultCollation("Latin1_General_CS_AS"); - // returned size is -1 - answerColumnDefs(new ColumnDef(TABLE_PROJECTS, COLUMN_NAME, "Latin1_General", "Latin1_General_CI_AI", "nvarchar", -1, false)); - answerIndices(); - - underTest.handle(connection, DatabaseCharsetChecker.State.UPGRADE); - - verify(sqlExecutor).executeDdl(connection, "ALTER TABLE projects ALTER COLUMN name nvarchar(max) COLLATE Latin1_General_CS_AS NOT NULL"); - } - - @Test - public void do_not_repair_system_tables_of_sql_azure() throws Exception { - answerDefaultCollation("Latin1_General_CS_AS"); - answerColumnDefs(new ColumnDef("sys.sysusers", COLUMN_NAME, "Latin1_General", "Latin1_General_CI_AI", "varchar", 10, false)); - - underTest.handle(connection, DatabaseCharsetChecker.State.UPGRADE); - - verify(sqlExecutor, never()).executeDdl(any(Connection.class), anyString()); - } - - @Test - @UseDataProvider("combinationOfBinAndSuffix") - public void do_not_repair_if_collation_contains_BIN(String collation) throws Exception { - answerDefaultCollation("Latin1_General_CS_AS"); - answerColumnDefs(new ColumnDef(TABLE_PROJECTS, COLUMN_NAME, "Latin1_General", collation, "varchar", 10, false)); - - underTest.handle(connection, DatabaseCharsetChecker.State.UPGRADE); - - verify(sqlExecutor, never()).executeDdl(any(Connection.class), anyString()); - } - - @DataProvider - public static Object[][] combinationOfBinAndSuffix() { - return Stream.of("", "_KS_WS") - .map(suffix -> new String[] {format("Latin1_General_BIN%s", suffix)}) - .toArray(Object[][]::new); - } - - @Test - @UseDataProvider("combinationOfBin2AndSuffix") - public void do_not_repair_if_collation_contains_BIN2(String collation) throws Exception { - answerDefaultCollation("Latin1_General_CS_AS"); - answerColumnDefs(new ColumnDef(TABLE_PROJECTS, COLUMN_NAME, "Latin1_General", collation, "varchar", 10, false)); - - underTest.handle(connection, DatabaseCharsetChecker.State.UPGRADE); - - verify(sqlExecutor, never()).executeDdl(any(Connection.class), anyString()); - } - - @DataProvider - public static Object[][] combinationOfBin2AndSuffix() { - return Stream.of("", "_KS_WS") - .map(suffix -> new String[] {format("Latin1_General_BIN2%s", suffix)}) - .toArray(Object[][]::new); - } - - /** - * SONAR-7988 - */ - @Test - public void fix_Latin1_CS_AS_columns_created_in_5_x() throws SQLException { - answerDefaultCollation("SQL_Latin1_General_CP1_CS_AS"); - answerColumnDefs(new ColumnDef(TABLE_PROJECTS, COLUMN_NAME, "Latin1_General", "Latin1_General_CS_AS", "nvarchar", 10, false)); - - underTest.handle(connection, DatabaseCharsetChecker.State.UPGRADE); - - verify(sqlExecutor).executeDdl(connection, "ALTER TABLE projects ALTER COLUMN name nvarchar(10) COLLATE SQL_Latin1_General_CP1_CS_AS NOT NULL"); - } - - private void answerColumnDefs(ColumnDef... columnDefs) throws SQLException { - when(metadata.getColumnDefs(connection)).thenReturn(asList(columnDefs)); - } - - private void answerDefaultCollation(String defaultCollation) throws SQLException { - when(metadata.getDefaultCollation(connection)).thenReturn(defaultCollation); - } - - private void answerIndices(MssqlCharsetHandler.ColumnIndex... indices) throws SQLException { - when(metadata.getColumnIndices(same(connection), any(ColumnDef.class))).thenReturn(asList(indices)); - } -} diff --git a/sonar-db/src/test/java/org/sonar/db/charset/MssqlMetadataReaderTest.java b/sonar-db/src/test/java/org/sonar/db/charset/MssqlMetadataReaderTest.java deleted file mode 100644 index 3901c201f68..00000000000 --- a/sonar-db/src/test/java/org/sonar/db/charset/MssqlMetadataReaderTest.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.db.charset; - -import java.sql.Connection; -import java.sql.SQLException; -import java.util.Arrays; -import java.util.List; -import org.junit.Test; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.same; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class MssqlMetadataReaderTest { - - private SqlExecutor sqlExecutor = mock(SqlExecutor.class); - private Connection connection = mock(Connection.class); - private MssqlMetadataReader underTest = new MssqlMetadataReader(sqlExecutor); - - @Test - public void test_getDefaultCollation() throws SQLException { - answerSelect(Arrays.<String[]>asList(new String[] {"Latin1_General_CS_AS"})); - - assertThat(underTest.getDefaultCollation(connection)).isEqualTo("Latin1_General_CS_AS"); - } - - private void answerSelect(List<String[]> firstRequest) throws SQLException { - when(sqlExecutor.select(same(connection), anyString(), any(SqlExecutor.StringsConverter.class))).thenReturn(firstRequest); - } -} diff --git a/sonar-db/src/test/java/org/sonar/db/charset/MysqlCharsetHandlerTest.java b/sonar-db/src/test/java/org/sonar/db/charset/MysqlCharsetHandlerTest.java deleted file mode 100644 index 8fc85450221..00000000000 --- a/sonar-db/src/test/java/org/sonar/db/charset/MysqlCharsetHandlerTest.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.db.charset; - -import java.sql.Connection; -import java.sql.SQLException; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -import static java.util.Arrays.asList; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; -import static org.mockito.Mockito.when; - -public class MysqlCharsetHandlerTest { - - private static final String TABLE_ISSUES = "issues"; - private static final String TABLE_PROJECTS = "projects"; - private static final String COLUMN_KEE = "kee"; - private static final String COLUMN_NAME = "name"; - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - private SqlExecutor sqlExecutor = mock(SqlExecutor.class); - private Connection connection = mock(Connection.class); - private MysqlCharsetHandler underTest = new MysqlCharsetHandler(sqlExecutor); - - @Test - public void upgrade_verifies_that_columns_are_utf8_and_case_sensitive() throws Exception { - answerColumnDef( - new ColumnDef(TABLE_ISSUES, COLUMN_KEE, "utf8", "utf8_bin", "varchar", 10, false), - new ColumnDef(TABLE_PROJECTS, COLUMN_NAME, "utf8", "utf8_bin", "varchar", 10, false)); - - // all columns are utf8 - underTest.handle(connection, DatabaseCharsetChecker.State.UPGRADE); - } - - @Test - public void fresh_install_does_not_verify_anything() throws Exception { - underTest.handle(connection, DatabaseCharsetChecker.State.FRESH_INSTALL); - verifyZeroInteractions(sqlExecutor); - } - - @Test - public void regular_startup_does_not_verify_anything() throws Exception { - underTest.handle(connection, DatabaseCharsetChecker.State.STARTUP); - verifyZeroInteractions(sqlExecutor); - } - - @Test - public void repair_case_insensitive_column() throws Exception { - answerColumnDef( - new ColumnDef(TABLE_ISSUES, COLUMN_KEE, "big5_chinese", "big5_chinese_ci", "varchar", 10, false), - new ColumnDef(TABLE_PROJECTS, COLUMN_NAME, "latin1", "latin1_swedish_ci", "varchar", 10, false)); - - underTest.handle(connection, DatabaseCharsetChecker.State.UPGRADE); - - verify(sqlExecutor).executeDdl(connection, "ALTER TABLE issues MODIFY kee varchar(10) CHARACTER SET 'big5_chinese' COLLATE 'big5_bin' NOT NULL"); - verify(sqlExecutor).executeDdl(connection, "ALTER TABLE projects MODIFY name varchar(10) CHARACTER SET 'latin1' COLLATE 'latin1_bin' NOT NULL"); - } - - @Test - public void size_should_be_ignored_on_longtext_column() throws Exception { - answerColumnDef( - new ColumnDef(TABLE_ISSUES, COLUMN_KEE, "latin1", "latin1_german1_ci", "longtext", 4_294_967_295L, false)); - - underTest.handle(connection, DatabaseCharsetChecker.State.UPGRADE); - - verify(sqlExecutor).executeDdl(connection, "ALTER TABLE " + TABLE_ISSUES + " MODIFY " + COLUMN_KEE + " longtext CHARACTER SET 'latin1' COLLATE 'latin1_bin' NOT NULL"); - } - - private void answerColumnDef(ColumnDef... columnDefs) throws SQLException { - when(sqlExecutor.select(any(Connection.class), anyString(), eq(ColumnDef.ColumnDefRowConverter.INSTANCE))) - .thenReturn(asList(columnDefs)); - } -} diff --git a/sonar-db/src/test/java/org/sonar/db/charset/OracleCharsetHandlerTest.java b/sonar-db/src/test/java/org/sonar/db/charset/OracleCharsetHandlerTest.java deleted file mode 100644 index f0474c2475b..00000000000 --- a/sonar-db/src/test/java/org/sonar/db/charset/OracleCharsetHandlerTest.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.db.charset; - -import java.sql.Connection; -import java.sql.SQLException; -import java.util.Collections; -import java.util.List; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.sonar.api.utils.MessageException; - -import static java.util.Collections.singletonList; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verifyZeroInteractions; -import static org.mockito.Mockito.when; - -public class OracleCharsetHandlerTest { - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - private SqlExecutor sqlExecutor = mock(SqlExecutor.class); - private Connection connection = mock(Connection.class); - private OracleCharsetHandler underTest = new OracleCharsetHandler(sqlExecutor); - - @Test - public void fresh_install_verifies_utf8_charset() throws Exception { - answerSql(singletonList(new String[] {"UTF8"}), singletonList(new String[] {"BINARY"})); - - underTest.handle(connection, DatabaseCharsetChecker.State.FRESH_INSTALL); - } - - @Test - public void upgrade_does_not_verify_utf8_charset() throws Exception { - underTest.handle(connection, DatabaseCharsetChecker.State.UPGRADE); - - verifyZeroInteractions(sqlExecutor); - } - - @Test - public void fresh_install_supports_al32utf8() throws Exception { - answerSql( - singletonList(new String[] {"AL32UTF8"}), singletonList(new String[] {"BINARY"})); - - underTest.handle(connection, DatabaseCharsetChecker.State.FRESH_INSTALL); - } - - @Test - public void fresh_install_fails_if_charset_is_not_utf8() throws Exception { - answerSql( - singletonList(new String[] {"LATIN"}), singletonList(new String[] {"BINARY"})); - - expectedException.expect(MessageException.class); - expectedException.expectMessage("Oracle must be have UTF8 charset and BINARY sort. NLS_CHARACTERSET is LATIN and NLS_SORT is BINARY."); - - underTest.handle(connection, DatabaseCharsetChecker.State.FRESH_INSTALL); - } - - @Test - public void fresh_install_fails_if_not_case_sensitive() throws Exception { - answerSql( - singletonList(new String[] {"UTF8"}), singletonList(new String[] {"LINGUISTIC"})); - - expectedException.expect(MessageException.class); - expectedException.expectMessage("Oracle must be have UTF8 charset and BINARY sort. NLS_CHARACTERSET is UTF8 and NLS_SORT is LINGUISTIC."); - - underTest.handle(connection, DatabaseCharsetChecker.State.FRESH_INSTALL); - } - - @Test - public void fails_if_can_not_get_charset() throws Exception { - answerSql(Collections.emptyList(), Collections.emptyList()); - - expectedException.expect(MessageException.class); - - underTest.handle(connection, DatabaseCharsetChecker.State.FRESH_INSTALL); - } - - @Test - public void does_nothing_if_regular_startup() throws Exception { - underTest.handle(connection, DatabaseCharsetChecker.State.STARTUP); - verifyZeroInteractions(sqlExecutor); - } - - private void answerSql(List<String[]> firstRequest, List<String[]>... otherRequests) throws SQLException { - when(sqlExecutor.select(any(Connection.class), anyString(), any(SqlExecutor.StringsConverter.class))).thenReturn(firstRequest, otherRequests); - } -} diff --git a/sonar-db/src/test/java/org/sonar/db/charset/PostgresCharsetHandlerTest.java b/sonar-db/src/test/java/org/sonar/db/charset/PostgresCharsetHandlerTest.java deleted file mode 100644 index 69f0fb76720..00000000000 --- a/sonar-db/src/test/java/org/sonar/db/charset/PostgresCharsetHandlerTest.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.db.charset; - -import java.sql.Connection; -import java.sql.SQLException; -import java.util.Arrays; -import java.util.List; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.sonar.api.utils.MessageException; - -import static java.util.Arrays.asList; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.same; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyZeroInteractions; -import static org.mockito.Mockito.when; - -public class PostgresCharsetHandlerTest { - - private static final String TABLE_ISSUES = "issues"; - private static final String TABLE_PROJECTS = "projects"; - private static final String COLUMN_KEE = "kee"; - private static final String COLUMN_NAME = "name"; - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - 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); - - @Test - public void fresh_install_verifies_that_default_charset_is_utf8() throws SQLException { - answerDefaultCharset("utf8"); - - underTest.handle(connection, DatabaseCharsetChecker.State.FRESH_INSTALL); - // no errors, charset has been verified - verify(metadata).getDefaultCharset(same(connection)); - verifyZeroInteractions(sqlExecutor); - } - - @Test - public void upgrade_verifies_that_default_charset_and_columns_are_utf8() throws Exception { - answerDefaultCharset("utf8"); - answerColumns(asList( - new String[] {TABLE_ISSUES, COLUMN_KEE, "utf8"}, - new String[] {TABLE_PROJECTS, COLUMN_NAME, "utf8"})); - - underTest.handle(connection, DatabaseCharsetChecker.State.UPGRADE); - // no errors, charsets have been verified - verify(metadata).getDefaultCharset(same(connection)); - } - - @Test - public void regular_startup_verifies_that_default_charset_and_columns_are_utf8() throws Exception { - answerDefaultCharset("utf8"); - answerColumns(asList( - new String[] {TABLE_ISSUES, COLUMN_KEE, "utf8"}, - new String[] {TABLE_PROJECTS, COLUMN_NAME, "utf8"})); - - underTest.handle(connection, DatabaseCharsetChecker.State.STARTUP); - // no errors, charsets have been verified - verify(metadata).getDefaultCharset(same(connection)); - } - - @Test - public void column_charset_can_be_empty() throws Exception { - answerDefaultCharset("utf8"); - answerColumns(asList( - new String[] {TABLE_ISSUES, COLUMN_KEE, "utf8"}, - new String[] {TABLE_PROJECTS, COLUMN_NAME, "" /* unset -> uses db collation */})); - - // no error - underTest.handle(connection, DatabaseCharsetChecker.State.UPGRADE); - } - - @Test - public void upgrade_fails_if_non_utf8_column() throws Exception { - // default charset is ok but two columns are not - answerDefaultCharset("utf8"); - answerColumns(asList( - new String[] {TABLE_ISSUES, COLUMN_KEE, "utf8"}, - new String[] {TABLE_PROJECTS, COLUMN_KEE, "latin"}, - new String[] {TABLE_PROJECTS, COLUMN_NAME, "latin"})); - - expectedException.expect(MessageException.class); - expectedException.expectMessage("Database columns [projects.kee, projects.name] must have UTF8 charset."); - - underTest.handle(connection, DatabaseCharsetChecker.State.UPGRADE); - } - - @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"})); - - expectedException.expect(MessageException.class); - expectedException.expectMessage("Database charset is latin. It must support UTF8."); - - underTest.handle(connection, DatabaseCharsetChecker.State.UPGRADE); - } - - private void answerDefaultCharset(String defaultCollation) throws SQLException { - when(metadata.getDefaultCharset(same(connection))).thenReturn(defaultCollation); - } - - private void answerColumns(List<String[]> firstRequest) throws SQLException { - when(sqlExecutor.select(same(connection), anyString(), any(SqlExecutor.StringsConverter.class))).thenReturn(firstRequest); - } -} diff --git a/sonar-db/src/test/java/org/sonar/db/charset/PostgresMetadataReaderTest.java b/sonar-db/src/test/java/org/sonar/db/charset/PostgresMetadataReaderTest.java deleted file mode 100644 index edcb4a823e9..00000000000 --- a/sonar-db/src/test/java/org/sonar/db/charset/PostgresMetadataReaderTest.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.db.charset; - -import java.sql.Connection; -import java.sql.SQLException; -import java.util.Arrays; -import java.util.List; -import org.junit.Test; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.same; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class PostgresMetadataReaderTest { - - private SqlExecutor sqlExecutor = mock(SqlExecutor.class); - private Connection connection = mock(Connection.class); - private PostgresMetadataReader underTest = new PostgresMetadataReader(sqlExecutor); - - @Test - public void test_getDefaultCharset() throws SQLException { - answerSelect(Arrays.<String[]>asList(new String[] {"latin"})); - - assertThat(underTest.getDefaultCharset(connection)).isEqualTo("latin"); - } - - private void answerSelect(List<String[]> firstRequest) throws SQLException { - when(sqlExecutor.select(same(connection), anyString(), any(SqlExecutor.StringsConverter.class))).thenReturn(firstRequest); - } - -} diff --git a/sonar-db/src/test/java/org/sonar/db/charset/SelectExecutorTest.java b/sonar-db/src/test/java/org/sonar/db/charset/SelectExecutorTest.java deleted file mode 100644 index bdcee828c2a..00000000000 --- a/sonar-db/src/test/java/org/sonar/db/charset/SelectExecutorTest.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.db.charset; - -import java.sql.Connection; -import java.util.List; -import org.junit.Rule; -import org.junit.Test; -import org.sonar.api.utils.System2; -import org.sonar.db.DbSession; -import org.sonar.db.DbTester; -import org.sonar.db.user.UserDto; - -import static org.assertj.core.api.Assertions.assertThat; - -public class SelectExecutorTest { - - @Rule - public DbTester dbTester = DbTester.create(System2.INSTANCE); - - SqlExecutor underTest = new SqlExecutor(); - - @Test - public void testExecuteQuery() throws Exception { - DbSession session = dbTester.getSession(); - dbTester.getDbClient().userDao().insert(session, new UserDto().setLogin("him").setName("Him")); - dbTester.getDbClient().userDao().insert(session, new UserDto().setLogin("her").setName("Her")); - session.commit(); - - try (Connection connection = dbTester.openConnection()) { - List<String[]> rows = underTest.select(connection, "select login, name from users order by login", new SqlExecutor.StringsConverter(2)); - assertThat(rows).hasSize(2); - assertThat(rows.get(0)[0]).isEqualTo("her"); - assertThat(rows.get(0)[1]).isEqualTo("Her"); - assertThat(rows.get(1)[0]).isEqualTo("him"); - assertThat(rows.get(1)[1]).isEqualTo("Him"); - } - } -} diff --git a/sonar-db/src/test/java/org/sonar/db/charset/SqlExecutorTest.java b/sonar-db/src/test/java/org/sonar/db/charset/SqlExecutorTest.java deleted file mode 100644 index c9ac2e5594a..00000000000 --- a/sonar-db/src/test/java/org/sonar/db/charset/SqlExecutorTest.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2016 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.db.charset; - -import java.sql.Connection; -import java.util.List; -import java.util.Map; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.sonar.api.utils.System2; -import org.sonar.db.DbTester; -import org.sonar.db.dialect.H2; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assume.assumeTrue; - -public class SqlExecutorTest { - - private static final String LOGIN_DB_COLUMN = "login"; - private static final String NAME_DB_COLUMN = "name"; - private static final String USERS_DB_TABLE = "users"; - private static final String IS_ROOT_DB_COLUMN = "is_root"; - - SqlExecutor underTest = new SqlExecutor(); - - @Rule - public DbTester dbTester = DbTester.create(System2.INSTANCE); - - @Before - public void disableIfNotH2() { - // TODO dbTester.selectFirst() returns keys with different case - // depending on target db (lower-case for MySQL but upper-case for H2). - // It has to be fixed in order to reactive this test for all dbs. - assumeTrue(dbTester.database().getDialect().getId().equals(H2.ID)); - } - - @Test - public void executeSelect_executes_PreparedStatement() throws Exception { - dbTester.executeInsert(USERS_DB_TABLE, LOGIN_DB_COLUMN, "login1", NAME_DB_COLUMN, "name one", IS_ROOT_DB_COLUMN, false); - dbTester.executeInsert(USERS_DB_TABLE, LOGIN_DB_COLUMN, "login2", NAME_DB_COLUMN, "name two", IS_ROOT_DB_COLUMN, false); - - try (Connection connection = dbTester.openConnection()) { - List<String[]> users = underTest.select(connection, "select " + LOGIN_DB_COLUMN + ", " + NAME_DB_COLUMN + " from users order by id", new SqlExecutor.StringsConverter( - 2)); - assertThat(users).hasSize(2); - assertThat(users.get(0)[0]).isEqualTo("login1"); - assertThat(users.get(0)[1]).isEqualTo("name one"); - assertThat(users.get(1)[0]).isEqualTo("login2"); - assertThat(users.get(1)[1]).isEqualTo("name two"); - } - } - - @Test - public void executeUpdate_executes_PreparedStatement() throws Exception { - dbTester.executeInsert(USERS_DB_TABLE, LOGIN_DB_COLUMN, "the_login", NAME_DB_COLUMN, "the name", IS_ROOT_DB_COLUMN, false); - - try (Connection connection = dbTester.openConnection()) { - underTest.executeDdl(connection, "update users set " + NAME_DB_COLUMN + "='new name' where " + LOGIN_DB_COLUMN + "='the_login'"); - } - Map<String, Object> row = dbTester.selectFirst("select " + NAME_DB_COLUMN + " from users where " + LOGIN_DB_COLUMN + "='the_login'"); - assertThat(row).isNotEmpty(); - assertThat(row.get("NAME")).isEqualTo("new name"); - } - -} |