From: Sébastien Lesaint Date: Thu, 1 Sep 2016 10:27:05 +0000 (+0200) Subject: SONAR-8058 move views.def from PROPERTIES to INTERNAL_PROPERTIES X-Git-Tag: 6.1-RC1~222 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=fefad99cac05440454dd61468c5bd48132f1ae5b;p=sonarqube.git SONAR-8058 move views.def from PROPERTIES to INTERNAL_PROPERTIES --- diff --git a/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1311_remove_views_definition_from_properties.rb b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1311_remove_views_definition_from_properties.rb new file mode 100644 index 00000000000..24a7648194e --- /dev/null +++ b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1311_remove_views_definition_from_properties.rb @@ -0,0 +1,30 @@ +# +# SonarQube, open source software quality management tool. +# Copyright (C) 2008-2014 SonarSource +# mailto:contact AT sonarsource DOT com +# +# SonarQube 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. +# +# SonarQube 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. +# + +# +# SonarQube 6.1 +# +class RemoveViewsDefinitionFromProperties < ActiveRecord::Migration + + def self.up + execute_java_migration('org.sonar.db.version.v61.RemoveViewsDefinitionFromProperties') + end + +end diff --git a/sonar-db/src/main/java/org/sonar/db/version/DatabaseVersion.java b/sonar-db/src/main/java/org/sonar/db/version/DatabaseVersion.java index 0645ef93da6..ec8736608ac 100644 --- a/sonar-db/src/main/java/org/sonar/db/version/DatabaseVersion.java +++ b/sonar-db/src/main/java/org/sonar/db/version/DatabaseVersion.java @@ -30,7 +30,7 @@ import org.sonar.db.MyBatis; public class DatabaseVersion { - public static final int LAST_VERSION = 1_310; + public static final int LAST_VERSION = 1_311; /** * The minimum supported version which can be upgraded. Lower diff --git a/sonar-db/src/main/java/org/sonar/db/version/MigrationStepModule.java b/sonar-db/src/main/java/org/sonar/db/version/MigrationStepModule.java index b30051b2c98..deae1edc772 100644 --- a/sonar-db/src/main/java/org/sonar/db/version/MigrationStepModule.java +++ b/sonar-db/src/main/java/org/sonar/db/version/MigrationStepModule.java @@ -149,6 +149,7 @@ import org.sonar.db.version.v61.AddErrorColumnsToCeActivity; import org.sonar.db.version.v61.DeleteProjectDashboards; import org.sonar.db.version.v61.DeleteReportsFromCeQueue; import org.sonar.db.version.v61.DropIsGlobalFromDashboards; +import org.sonar.db.version.v61.RemoveViewsDefinitionFromProperties; import org.sonar.db.version.v61.ShrinkModuleUuidPathOfProjects; public class MigrationStepModule extends Module { @@ -318,6 +319,7 @@ public class MigrationStepModule extends Module { DeleteReportsFromCeQueue.class, ShrinkModuleUuidPathOfProjects.class, AddBUuidPathToProjects.class, - AddErrorColumnsToCeActivity.class); + AddErrorColumnsToCeActivity.class, + RemoveViewsDefinitionFromProperties.class); } } diff --git a/sonar-db/src/main/java/org/sonar/db/version/v61/RemoveViewsDefinitionFromProperties.java b/sonar-db/src/main/java/org/sonar/db/version/v61/RemoveViewsDefinitionFromProperties.java new file mode 100644 index 00000000000..389a5f7666e --- /dev/null +++ b/sonar-db/src/main/java/org/sonar/db/version/v61/RemoveViewsDefinitionFromProperties.java @@ -0,0 +1,86 @@ +/* + * 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.version.v61; + +import java.sql.SQLException; +import javax.annotation.Nullable; +import org.sonar.api.utils.System2; +import org.sonar.db.Database; +import org.sonar.db.version.BaseDataChange; +import org.sonar.db.version.Upsert; + +public class RemoveViewsDefinitionFromProperties extends BaseDataChange { + + private static final String VIEWS_DEFINITION_PROPERTY_KEY = "views.def"; + private static final int VARCHAR_MAX_LENGTH = 4000; + + private final System2 system2; + + public RemoveViewsDefinitionFromProperties(Database db, System2 system2) { + super(db); + this.system2 = system2; + } + + @Override + public void execute(Context context) throws SQLException { + String property = context + .prepareSelect("select text_value from properties where prop_key=?") + .setString(1, VIEWS_DEFINITION_PROPERTY_KEY) + .get(row -> row.getNullableString(1)); + Integer hasInternalProperty = context + .prepareSelect("select 1 from internal_properties where kee=?") + .setString(1, VIEWS_DEFINITION_PROPERTY_KEY) + .get(row -> row.getNullableInt(1)); + + if (hasInternalProperty == null) { + addToInternalProperties(context, property); + } + deleteFromProperties(context); + } + + private void addToInternalProperties(Context context, @Nullable String property) throws SQLException { + if (property != null) { + boolean mustBeStoredInClob = property.length() > VARCHAR_MAX_LENGTH; + try (Upsert insert = context.prepareUpsert("insert into internal_properties" + + " (kee, is_empty, " + (mustBeStoredInClob ? "clob_value" : "text_value") + ", created_at)" + + " values" + + " (?,?,?,?)")) { + long now = system2.now(); + insert + .setString(1, "xmlDefinition") + .setBoolean(2, false) + .setString(3, property) + .setLong(4, now) + .execute() + .commit(); + } + } + } + + private static void deleteFromProperties(Context context) throws SQLException { + try (Upsert delete = context.prepareUpsert("delete from properties where prop_key=?")) { + delete + .setString(1, VIEWS_DEFINITION_PROPERTY_KEY) + .execute() + .commit(); + } + } + +} diff --git a/sonar-db/src/main/resources/org/sonar/db/version/rows-h2.sql b/sonar-db/src/main/resources/org/sonar/db/version/rows-h2.sql index 48eccb51e08..507c13be8f8 100644 --- a/sonar-db/src/main/resources/org/sonar/db/version/rows-h2.sql +++ b/sonar-db/src/main/resources/org/sonar/db/version/rows-h2.sql @@ -495,6 +495,7 @@ INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1306'); INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1307'); INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1309'); INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1310'); +INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1311'); INSERT INTO USERS(ID, LOGIN, NAME, EMAIL, EXTERNAL_IDENTITY, EXTERNAL_IDENTITY_PROVIDER, USER_LOCAL, CRYPTED_PASSWORD, SALT, CREATED_AT, UPDATED_AT) VALUES (1, 'admin', 'Administrator', '', 'admin', 'sonarqube', true, 'a373a0e667abb2604c1fd571eb4ad47fe8cc0878', '48bc4b0d93179b5103fd3885ea9119498e9d161b', '1418215735482', '1418215735482'); ALTER TABLE USERS ALTER COLUMN ID RESTART WITH 2; diff --git a/sonar-db/src/test/java/org/sonar/db/version/MigrationStepModuleTest.java b/sonar-db/src/test/java/org/sonar/db/version/MigrationStepModuleTest.java index dffa71a16b9..271e5209b59 100644 --- a/sonar-db/src/test/java/org/sonar/db/version/MigrationStepModuleTest.java +++ b/sonar-db/src/test/java/org/sonar/db/version/MigrationStepModuleTest.java @@ -29,6 +29,6 @@ public class MigrationStepModuleTest { public void verify_count_of_added_MigrationStep_types() { ComponentContainer container = new ComponentContainer(); new MigrationStepModule().configure(container); - assertThat(container.size()).isEqualTo(132); + assertThat(container.size()).isEqualTo(133); } } diff --git a/sonar-db/src/test/java/org/sonar/db/version/v61/RemoveViewsDefinitionFromPropertiesTest.java b/sonar-db/src/test/java/org/sonar/db/version/v61/RemoveViewsDefinitionFromPropertiesTest.java new file mode 100644 index 00000000000..cb5a713705a --- /dev/null +++ b/sonar-db/src/test/java/org/sonar/db/version/v61/RemoveViewsDefinitionFromPropertiesTest.java @@ -0,0 +1,97 @@ +/* + * 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.version.v61; + +import java.sql.SQLException; +import java.util.List; +import java.util.Map; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.sonar.api.utils.System2; +import org.sonar.db.DbTester; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +public class RemoveViewsDefinitionFromPropertiesTest { + + private static final long NOW = 1_500_000_000_000L; + + @Rule + public ExpectedException expectedException = ExpectedException.none(); + @Rule + public DbTester db = DbTester.createForSchema(System2.INSTANCE, RemoveViewsDefinitionFromPropertiesTest.class, "properties_and_internal_properties.sql"); + + private System2 system2 = spy(System2.INSTANCE); + private RemoveViewsDefinitionFromProperties underTest = new RemoveViewsDefinitionFromProperties(db.database(), system2); + + @Test + public void ignore_missing_views_definition() throws SQLException { + underTest.execute(); + + assertThat(db.countRowsOfTable("internal_properties")).isEqualTo(0); + } + + @Test + public void move_views_definition_from_properties_to_text_value_of_internal_properties_table_when_less_than_4000() throws SQLException { + executeAndVerify("views content", false); + } + + @Test + public void move_views_definition_from_properties_to_text_value_of_internal_properties_table_when_is_4000() throws SQLException { + executeAndVerify(String.format("%1$4000.4000s", "*"), false); + } + + @Test + public void move_views_definition_from_properties_to_clob_value_of_internal_properties_table_when_is_more_than_4000() throws SQLException { + executeAndVerify(String.format("%1$4000.4000s", "*") + "abc", true); + } + + private void executeAndVerify(String xml, boolean isClob) throws SQLException { + when(system2.now()).thenReturn(NOW); + db.executeInsert("properties", "prop_key", "views.def", "text_value", xml); + db.executeInsert("properties", "prop_key", "other.property", "text_value", "other content"); + + underTest.execute(); + + assertThat(db.countRowsOfTable("internal_properties")).isEqualTo(1); + Map internalProp = db.selectFirst("select" + + " kee as \"key\", is_empty as \"isEmpty\", text_value as \"textValue\", clob_value as \"clobValue\", created_at as \"createdAt\"" + + " from internal_properties"); + assertThat(internalProp.get("key")).isEqualTo("xmlDefinition"); + assertThat(internalProp.get("isEmpty")).isEqualTo(false); + if (isClob) { + assertThat(internalProp.get("clobValue")).isEqualTo(xml); + assertThat(internalProp.get("textValue")).isNull(); + } else { + assertThat(internalProp.get("textValue")).isEqualTo(xml); + assertThat(internalProp.get("clobValue")).isNull(); + } + assertThat(internalProp.get("createdAt")).isEqualTo(NOW); + + // property "views.def" has been deleted + List> properties = db.select("select prop_key as \"prop_key\" from properties"); + assertThat(properties).hasSize(1); + assertThat(properties.get(0).get("prop_key")).isEqualTo("other.property"); + } + +} diff --git a/sonar-db/src/test/resources/org/sonar/db/version/v61/RemoveViewsDefinitionFromPropertiesTest/properties_and_internal_properties.sql b/sonar-db/src/test/resources/org/sonar/db/version/v61/RemoveViewsDefinitionFromPropertiesTest/properties_and_internal_properties.sql new file mode 100644 index 00000000000..e38510f469a --- /dev/null +++ b/sonar-db/src/test/resources/org/sonar/db/version/v61/RemoveViewsDefinitionFromPropertiesTest/properties_and_internal_properties.sql @@ -0,0 +1,17 @@ +CREATE TABLE "PROPERTIES" ( + "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), + "PROP_KEY" VARCHAR(512), + "RESOURCE_ID" INTEGER, + "TEXT_VALUE" CLOB(2147483647), + "USER_ID" INTEGER +); + +CREATE TABLE "INTERNAL_PROPERTIES" ( + "KEE" VARCHAR(50) NOT NULL PRIMARY KEY, + "IS_EMPTY" BOOLEAN NOT NULL, + "TEXT_VALUE" VARCHAR(4000), + "CLOB_VALUE" CLOB, + "CREATED_AT" BIGINT +); + +CREATE UNIQUE INDEX "UNIQ_INTERNAL_PROPERTIES" ON "INTERNAL_PROPERTIES" ("KEE");