diff options
author | lukasz-jarocki-sonarsource <lukasz.jarocki@sonarsource.com> | 2024-06-20 11:53:46 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2024-06-20 20:02:37 +0000 |
commit | 7f3b10b7230b99f85b173971c545505817b5c1b1 (patch) | |
tree | 05f839e20d590fe6b8ed350d2826ba71e04eb0bc /server | |
parent | 9cba9be776f8017e95f1b0f6cd73d280336ade50 (diff) | |
download | sonarqube-7f3b10b7230b99f85b173971c545505817b5c1b1.tar.gz sonarqube-7f3b10b7230b99f85b173971c545505817b5c1b1.zip |
SONAR-21920 fixed issues in migrations 10_4_002 and 10_4_003
Diffstat (limited to 'server')
8 files changed, 190 insertions, 19 deletions
diff --git a/server/sonar-db-dao/src/schema/schema-sq.ddl b/server/sonar-db-dao/src/schema/schema-sq.ddl index 0825583478d..dbe7d4108fe 100644 --- a/server/sonar-db-dao/src/schema/schema-sq.ddl +++ b/server/sonar-db-dao/src/schema/schema-sq.ddl @@ -922,7 +922,7 @@ CREATE TABLE "RULE_REPOSITORIES"( ALTER TABLE "RULE_REPOSITORIES" ADD CONSTRAINT "PK_RULE_REPOSITORIES" PRIMARY KEY("KEE"); CREATE TABLE "RULE_TAGS"( - "VALUE" CHARACTER VARYING(40) NOT NULL, + "VALUE" CHARACTER VARYING(400) NOT NULL, "RULE_UUID" CHARACTER VARYING(40) NOT NULL, "IS_SYSTEM_TAG" BOOLEAN NOT NULL ); diff --git a/server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v104/PopulateRuleTagsTableIT.java b/server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v104/PopulateRuleTagsTableIT.java index f7bb7df824b..117cb025b86 100644 --- a/server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v104/PopulateRuleTagsTableIT.java +++ b/server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v104/PopulateRuleTagsTableIT.java @@ -75,6 +75,21 @@ class PopulateRuleTagsTableIT { } @Test + void execute_whenSystemAndCustomTagShareTheSameTag_removeDuplicates() throws SQLException { + insertRule("uuid-1", "test,other1", "test,other2"); + + migration.execute(); + + assertThat(db.select("select value, is_system_tag, rule_uuid from rule_tags")) + .extracting(t -> t.get("value"), t -> t.get("is_system_tag"), t -> t.get("rule_uuid")) + .containsExactlyInAnyOrder( + tuple("test", true, "uuid-1"), + tuple("other1", true, "uuid-1"), + tuple("other2", false, "uuid-1") + ); + } + + @Test void execute_whenRunMoreThanOnce_shouldBeReentrant() throws SQLException { insertRule("uuid-3", "sys_tag", "tag"); migration.execute(); @@ -86,7 +101,7 @@ class PopulateRuleTagsTableIT { private void verifyMapping() { assertThat(db.select("select value, is_system_tag, rule_uuid from rule_tags")) .extracting(t -> t.get("value"), t -> t.get("is_system_tag"), t -> t.get("rule_uuid")) - .containsExactly( + .containsExactlyInAnyOrder( tuple("sys_tag", true, "uuid-3"), tuple("tag", false, "uuid-3") ); diff --git a/server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v106/ResizeValueColumnInRuleTagsTableIT.java b/server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v106/ResizeValueColumnInRuleTagsTableIT.java new file mode 100644 index 00000000000..1335c194bb7 --- /dev/null +++ b/server/sonar-db-migration/src/it/java/org/sonar/server/platform/db/migration/version/v106/ResizeValueColumnInRuleTagsTableIT.java @@ -0,0 +1,65 @@ +/* + * SonarQube + * Copyright (C) 2009-2024 SonarSource SA + * mailto:info 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.server.platform.db.migration.version.v106; + +import java.sql.SQLException; +import java.sql.Types; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.sonar.db.CoreDbTester; +import org.sonar.db.MigrationDbTester; +import org.sonar.server.platform.db.migration.version.v104.CreateRuleTagsTable; + +class ResizeValueColumnInRuleTagsTableIT { + + private static final String EXPECTED_TABLE_NAME = "rule_tags"; + private static final String EXPECTED_COLUMN_NAME = "value"; + + /** + * This is database that has run the new version of the {@link CreateRuleTagsTable} migration with the 400 limit of the value column. + */ + @RegisterExtension + public final MigrationDbTester dbWith400LimitOnValueColumn = MigrationDbTester.createForMigrationStep(ResizeValueColumnInRuleTagsTable.class); + + /** + * This is the database that has run the old version of the {@link CreateRuleTagsTable} migration with the 40 limit of the value column. + */ + @RegisterExtension + public final CoreDbTester dbWith40LimitOnValueColumn = CoreDbTester.createForSchema(ResizeValueColumnInRuleTagsTableIT.class, "schema.sql"); + + private final ResizeValueColumnInRuleTagsTable underTestNoAction = new ResizeValueColumnInRuleTagsTable(dbWith400LimitOnValueColumn.database()); + private final ResizeValueColumnInRuleTagsTable underTestThatFixesColumnSize = new ResizeValueColumnInRuleTagsTable(dbWith40LimitOnValueColumn.database()); + + @Test + void execute_whenColumnIsNotResized_shouldResizeTheColumn() throws SQLException { + dbWith40LimitOnValueColumn.assertColumnDefinition(EXPECTED_TABLE_NAME, EXPECTED_COLUMN_NAME, Types.VARCHAR, 40, false); + underTestThatFixesColumnSize.execute(); + dbWith40LimitOnValueColumn.assertColumnDefinition(EXPECTED_TABLE_NAME, EXPECTED_COLUMN_NAME, Types.VARCHAR, 400, false); + } + + @Test + void execute_whenColumnIsAlreadyResized_shouldDoNothing() throws SQLException { + dbWith400LimitOnValueColumn.assertColumnDefinition(EXPECTED_TABLE_NAME, EXPECTED_COLUMN_NAME, Types.VARCHAR, 400, false); + underTestNoAction.execute(); + dbWith400LimitOnValueColumn.assertColumnDefinition(EXPECTED_TABLE_NAME, EXPECTED_COLUMN_NAME, Types.VARCHAR, 400, false); + } + + +} diff --git a/server/sonar-db-migration/src/it/resources/org/sonar/server/platform/db/migration/version/v106/ResizeValueColumnInRuleTagsTableIT/schema.sql b/server/sonar-db-migration/src/it/resources/org/sonar/server/platform/db/migration/version/v106/ResizeValueColumnInRuleTagsTableIT/schema.sql new file mode 100644 index 00000000000..ed4f3118592 --- /dev/null +++ b/server/sonar-db-migration/src/it/resources/org/sonar/server/platform/db/migration/version/v106/ResizeValueColumnInRuleTagsTableIT/schema.sql @@ -0,0 +1,5 @@ +CREATE TABLE "RULE_TAGS"( + "RULE_UUID" CHARACTER VARYING(40) NOT NULL, + "IS_SYSTEM_TAG" BOOLEAN NOT NULL, + "VALUE" CHARACTER VARYING(40) NOT NULL +);
\ No newline at end of file diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v104/CreateRuleTagsTable.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v104/CreateRuleTagsTable.java index 7ca48fc304e..19852d1939a 100644 --- a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v104/CreateRuleTagsTable.java +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v104/CreateRuleTagsTable.java @@ -32,11 +32,10 @@ public class CreateRuleTagsTable extends CreateTableChange { static final String RULE_TAGS_TABLE_NAME = "rule_tags"; - static final String UUID_COLUMN_NAME = "uuid"; static final String VALUE_COLUMN_NAME = "value"; static final String IS_SYSTEM_TAG_COLUMN_NAME = "is_system_tag"; static final String RULE_UUID_COLUMN_NAME = "rule_uuid"; - static final int VALUE_COLUMN_SIZE = 40; + static final int VALUE_COLUMN_SIZE = 400; public CreateRuleTagsTable(Database db) { super(db, RULE_TAGS_TABLE_NAME); diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v104/PopulateRuleTagsTable.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v104/PopulateRuleTagsTable.java index 25aca8cbbc8..e9564a8faf6 100644 --- a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v104/PopulateRuleTagsTable.java +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v104/PopulateRuleTagsTable.java @@ -20,8 +20,11 @@ package org.sonar.server.platform.db.migration.version.v104; import java.sql.SQLException; +import java.util.ArrayList; import java.util.Arrays; +import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @@ -33,14 +36,14 @@ import org.sonar.server.platform.db.migration.step.Upsert; public class PopulateRuleTagsTable extends DataChange { private static final String SELECT_QUERY = """ - SELECT uuid, system_tags AS tag, 1 as is_system_tag - FROM rules - WHERE system_tags IS NOT NULL - UNION ALL - SELECT uuid, tags AS tag, 0 as is_system_tag - FROM rules - WHERE tags IS NOT NULL - """; + SELECT uuid, system_tags AS tag, 1 as is_system_tag + FROM rules + WHERE system_tags IS NOT NULL + UNION ALL + SELECT uuid, tags AS tag, 0 as is_system_tag + FROM rules + WHERE tags IS NOT NULL + """; private static final String INSERT_QUERY = """ INSERT INTO rule_tags (rule_uuid, is_system_tag, value) @@ -57,18 +60,55 @@ public class PopulateRuleTagsTable extends DataChange { return; } - List<PopulateRuleTagsTable.Tag> allTags = findAllTags(context); + List<Tags> allTags = findAllTags(context); if (allTags.isEmpty()) { return; } + allTags = removeDuplicatesForAllRule(allTags); Upsert insertTagsQuery = context.prepareUpsert(INSERT_QUERY); - for (PopulateRuleTagsTable.Tag tag : allTags) { - insertEveryTag(insertTagsQuery, tag.ruleUuid(), tag.values(), tag.isSystemTag()); + for (Tags tags : allTags) { + insertEveryTag(insertTagsQuery, tags.ruleUuid(), tags.values(), tags.isSystemTag()); } insertTagsQuery.execute().commit(); } + /** + * System tags and custom tags can contain the same values. In this case, we keep only the system tag. + */ + private static List<Tags> removeDuplicatesForAllRule(List<Tags> allTags) { + Map<String, List<Tags>> tagsByRuleUuid = allTags.stream().collect(Collectors.groupingBy(Tags::ruleUuid)); + List<Tags> listWithoutDuplicates = new ArrayList<>(); + + for (Map.Entry<String, List<Tags>> entry : tagsByRuleUuid.entrySet()) { + listWithoutDuplicates.addAll(removeDuplicateForRule(entry.getValue())); + } + return listWithoutDuplicates; + } + + private static List<Tags> removeDuplicateForRule(List<Tags> ruleTags) { + Optional<Tags> systemTags = ruleTags.stream().filter(Tags::isSystemTag).findFirst(); + Optional<Tags> manualTags = ruleTags.stream().filter(t -> !t.isSystemTag()).findFirst(); + + if (systemTags.isEmpty()) { + return List.of(manualTags.orElseThrow()); + } else if (manualTags.isEmpty()) { + return List.of(systemTags.orElseThrow()); + } else { + Set<String> systemTagValues = systemTags.get().values(); + Set<String> manualTagValues = manualTags.get().values(); + Set<String> commonValues = new HashSet<>(systemTagValues); + commonValues.retainAll(manualTagValues); + + if (commonValues.isEmpty()) { + return List.of(manualTags.orElseThrow(), systemTags.orElseThrow()); + } else { + manualTagValues.removeAll(commonValues); + return List.of(systemTags.orElseThrow(), new Tags(manualTags.get().ruleUuid(), manualTagValues, false)); + } + } + } + private static void insertEveryTag(Upsert insertRuleTags, String ruleUuid, Set<String> values, boolean isSystemTag) throws SQLException { for (String tag : values) { insertRuleTags @@ -79,9 +119,9 @@ public class PopulateRuleTagsTable extends DataChange { } } - private static List<PopulateRuleTagsTable.Tag> findAllTags(Context context) throws SQLException { + private static List<Tags> findAllTags(Context context) throws SQLException { return context.prepareSelect(SELECT_QUERY) - .list(r -> new PopulateRuleTagsTable.Tag(r.getString(1), parseTagString(r.getString(2)), r.getBoolean(3))); + .list(r -> new Tags(r.getString(1), parseTagString(r.getString(2)), r.getBoolean(3))); } private static boolean isTableAlreadyPopulated(Context context) throws SQLException { @@ -97,7 +137,7 @@ public class PopulateRuleTagsTable extends DataChange { .collect(Collectors.toSet()); } - private record Tag(String ruleUuid, Set<String> values, boolean isSystemTag) { + private record Tags(String ruleUuid, Set<String> values, boolean isSystemTag) { } } diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v106/DbVersion106.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v106/DbVersion106.java index 61507231cf0..6f1ded53b60 100644 --- a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v106/DbVersion106.java +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v106/DbVersion106.java @@ -42,6 +42,7 @@ public class DbVersion106 implements DbVersion { public void addSteps(MigrationStepRegistry registry) { registry .add(10_6_000,"Add 'prioritized_rule' column to 'issues' table", AddPrioritizedRuleColumnToIssuesTable.class) - .add(10_6_001,"Add 'prioritized_rule' column to 'active_rules' table", AddPrioritizedRuleColumnToActiveRulesTable.class); + .add(10_6_001,"Add 'prioritized_rule' column to 'active_rules' table", AddPrioritizedRuleColumnToActiveRulesTable.class) + .add(10_6_002,"Ensure 'value' column is resized to 400 in 'rule_tags' table", ResizeValueColumnInRuleTagsTable.class); } } diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v106/ResizeValueColumnInRuleTagsTable.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v106/ResizeValueColumnInRuleTagsTable.java new file mode 100644 index 00000000000..9c512b57d66 --- /dev/null +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v106/ResizeValueColumnInRuleTagsTable.java @@ -0,0 +1,46 @@ +/* + * SonarQube + * Copyright (C) 2009-2024 SonarSource SA + * mailto:info 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.server.platform.db.migration.version.v106; + +import java.sql.SQLException; +import org.sonar.db.Database; +import org.sonar.server.platform.db.migration.def.VarcharColumnDef; +import org.sonar.server.platform.db.migration.sql.AlterColumnsBuilder; +import org.sonar.server.platform.db.migration.step.DdlChange; + +public class ResizeValueColumnInRuleTagsTable extends DdlChange { + + private static final VarcharColumnDef columnDefinition = VarcharColumnDef.newVarcharColumnDefBuilder() + .setColumnName("value") + .setIsNullable(false) + .setLimit(400) + .build(); + + public ResizeValueColumnInRuleTagsTable(Database db) { + super(db); + } + + @Override + public void execute(Context context) throws SQLException { + context.execute(new AlterColumnsBuilder(getDialect(), "rule_tags") + .updateColumn(columnDefinition) + .build()); + } +} |