--- /dev/null
+#
+# 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
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
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 {
DeleteReportsFromCeQueue.class,
ShrinkModuleUuidPathOfProjects.class,
AddBUuidPathToProjects.class,
- AddErrorColumnsToCeActivity.class);
+ AddErrorColumnsToCeActivity.class,
+ RemoveViewsDefinitionFromProperties.class);
}
}
--- /dev/null
+/*
+ * 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();
+ }
+ }
+
+}
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;
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);
}
}
--- /dev/null
+/*
+ * 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<String, Object> 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<Map<String, Object>> 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");
+ }
+
+}
--- /dev/null
+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");