]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-6840 Group migrations touching same table 514/head
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Thu, 17 Sep 2015 16:14:59 +0000 (18:14 +0200)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Fri, 18 Sep 2015 13:35:03 +0000 (15:35 +0200)
 Migrations that are done on the same table are now executed with only one SQL query

12 files changed:
server/sonar-web/src/main/webapp/WEB-INF/db/migrate/928_increase_precision_of_numerics.rb [deleted file]
server/sonar-web/src/main/webapp/WEB-INF/db/migrate/931_increase_precision_of_numerics.rb [new file with mode: 0644]
sonar-db/src/main/java/org/sonar/db/version/AlterColumnsBuilder.java [new file with mode: 0644]
sonar-db/src/main/java/org/sonar/db/version/DatabaseVersion.java
sonar-db/src/main/java/org/sonar/db/version/DecimalColumnDef.java [new file with mode: 0644]
sonar-db/src/main/java/org/sonar/db/version/MigrationStepModule.java
sonar-db/src/main/java/org/sonar/db/version/v52/IncreasePrecisionOfNumerics.java [new file with mode: 0644]
sonar-db/src/main/resources/org/sonar/db/version/rows-h2.sql
sonar-db/src/test/java/org/sonar/db/version/AlterColumnsBuilderTest.java [new file with mode: 0644]
sonar-db/src/test/java/org/sonar/db/version/DecimalColumnDefTest.java [new file with mode: 0644]
sonar-db/src/test/java/org/sonar/db/version/MigrationStepModuleTest.java
sonar-db/src/test/java/org/sonar/db/version/v52/IncreasePrecisionOfNumericsTest.java [new file with mode: 0644]

diff --git a/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/928_increase_precision_of_numerics.rb b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/928_increase_precision_of_numerics.rb
deleted file mode 100644 (file)
index cf8874f..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-#
-# 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 5.2
-# SONAR-6710
-#
-class IncreasePrecisionOfNumerics < ActiveRecord::Migration
-
-  def self.up
-    change_column :metrics, :worst_value, :decimal,  :null => true, :precision => 30, :scale => 5
-    change_column :metrics, :best_value, :decimal,  :null => true, :precision => 30, :scale => 5
-    change_column :project_measures, :value, :decimal,  :null => true, :precision => 30, :scale => 5
-    change_column :project_measures, :variation_value_1, :decimal,  :null => true, :precision => 30, :scale => 5
-    change_column :project_measures, :variation_value_2, :decimal,  :null => true, :precision => 30, :scale => 5
-    change_column :project_measures, :variation_value_3, :decimal,  :null => true, :precision => 30, :scale => 5
-    change_column :project_measures, :variation_value_4, :decimal,  :null => true, :precision => 30, :scale => 5
-    change_column :project_measures, :variation_value_5, :decimal,  :null => true, :precision => 30, :scale => 5
-    change_column :manual_measures, :value, :decimal,  :null => true, :precision => 30, :scale => 5
-  end
-
-end
diff --git a/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/931_increase_precision_of_numerics.rb b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/931_increase_precision_of_numerics.rb
new file mode 100644 (file)
index 0000000..aa86563
--- /dev/null
@@ -0,0 +1,31 @@
+#
+# 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 5.2
+# SONAR-6710
+#
+class IncreasePrecisionOfNumerics < ActiveRecord::Migration
+
+  def self.up
+    execute_java_migration('org.sonar.db.version.v52.IncreasePrecisionOfNumerics')
+  end
+
+end
diff --git a/sonar-db/src/main/java/org/sonar/db/version/AlterColumnsBuilder.java b/sonar-db/src/main/java/org/sonar/db/version/AlterColumnsBuilder.java
new file mode 100644 (file)
index 0000000..eda2a56
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * 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.
+ */
+
+package org.sonar.db.version;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import org.sonar.db.dialect.Dialect;
+import org.sonar.db.dialect.MySql;
+import org.sonar.db.dialect.Oracle;
+import org.sonar.db.dialect.PostgreSql;
+
+import static com.google.common.collect.Lists.newArrayList;
+
+/**
+ * Generate SQL queries to update multiple column types from a table.
+ *
+ * Note that it's not possible to change the nullable state of a column (Because on Oracle, sending a query to set a column to be nullable when it's already nullable will fail).
+ */
+public class AlterColumnsBuilder {
+
+  private final Dialect dialect;
+  private final String tableName;
+  private final List<ColumnDef> columnDefs = newArrayList();
+
+  public AlterColumnsBuilder(Dialect dialect, String tableName) {
+    this.dialect = dialect;
+    this.tableName = tableName;
+  }
+
+  public AlterColumnsBuilder updateColumn(ColumnDef columnDef) {
+    columnDefs.add(columnDef);
+    return this;
+  }
+
+  public List<String> build() {
+    if (columnDefs.isEmpty()) {
+      throw new IllegalStateException("No column has been defined");
+    }
+    switch (dialect.getId()) {
+      case PostgreSql.ID:
+        return createPostgresQuery();
+      case MySql.ID:
+        return createMySqlQuery();
+      case Oracle.ID:
+        return createOracleQuery();
+      default:
+        return createMySqlAndH2Queries();
+    }
+  }
+
+  private List<String> createPostgresQuery() {
+    StringBuilder sql = new StringBuilder("ALTER TABLE " + tableName + " ");
+    addColumns(sql, "ALTER COLUMN ", "TYPE ");
+    return Collections.singletonList(sql.toString());
+  }
+
+  private List<String> createMySqlQuery() {
+    StringBuilder sql = new StringBuilder("ALTER TABLE " + tableName + " ");
+    addColumns(sql, "MODIFY COLUMN ", "");
+    return Collections.singletonList(sql.toString());
+  }
+
+  private List<String> createOracleQuery() {
+    StringBuilder sql = new StringBuilder("ALTER TABLE " + tableName + " ").append("MODIFY (");
+    addColumns(sql, "", "");
+    sql.append(")");
+    return Collections.singletonList(sql.toString());
+  }
+
+  private List<String> createMySqlAndH2Queries() {
+    List<String> sqls = new ArrayList<>();
+    for (ColumnDef columnDef : columnDefs) {
+      StringBuilder defaultQuery = new StringBuilder("ALTER TABLE " + tableName + " ");
+      defaultQuery.append("ALTER COLUMN ");
+      addColumn(defaultQuery, columnDef, "");
+      sqls.add(defaultQuery.toString());
+    }
+    return sqls;
+  }
+
+  private void addColumns(StringBuilder sql, String updateKeyword, String typePrefix) {
+    for (Iterator<ColumnDef> columnDefIterator = columnDefs.iterator(); columnDefIterator.hasNext();) {
+      sql.append(updateKeyword);
+      addColumn(sql, columnDefIterator.next(), typePrefix);
+      if (columnDefIterator.hasNext()) {
+        sql.append(", ");
+      }
+    }
+  }
+
+  private void addColumn(StringBuilder sql, ColumnDef columnDef, String typePrefix) {
+    sql.append(columnDef.getName())
+      .append(" ")
+      .append(typePrefix)
+      .append(columnDef.generateSqlType(dialect));
+  }
+
+}
index f362a4c9693834e7bfbe2163bb66a35c7f5f3fba..c8a0ded3816c30c36a7dc74456061d71e81a3c06 100644 (file)
@@ -29,7 +29,7 @@ import org.sonar.db.MyBatis;
 
 public class DatabaseVersion {
 
-  public static final int LAST_VERSION = 930;
+  public static final int LAST_VERSION = 931;
 
   /**
    * The minimum supported version which can be upgraded. Lower
diff --git a/sonar-db/src/main/java/org/sonar/db/version/DecimalColumnDef.java b/sonar-db/src/main/java/org/sonar/db/version/DecimalColumnDef.java
new file mode 100644 (file)
index 0000000..e131f91
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * 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.
+ */
+
+package org.sonar.db.version;
+
+import javax.annotation.CheckForNull;
+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.sonar.db.version.ColumnDefValidation.validateColumnName;
+
+public class DecimalColumnDef extends AbstractColumnDef {
+
+  public static int DEFAULT_PRECISION = 38;
+  public static int DEFAULT_SACLE = 20;
+
+  private final int precision;
+  private final int scale;
+
+  private DecimalColumnDef(Builder builder) {
+    super(builder.columnName, builder.isNullable);
+    this.precision = builder.precision;
+    this.scale = builder.scale;
+  }
+
+  public static Builder newDecimalColumnDefBuilder() {
+    return new Builder();
+  }
+
+  public int getPrecision() {
+    return precision;
+  }
+
+  public int getScale() {
+    return scale;
+  }
+
+  @Override
+  public String generateSqlType(Dialect dialect) {
+    switch (dialect.getId()) {
+      case PostgreSql.ID:
+      case Oracle.ID:
+        return String.format("NUMERIC (%s,%s)", precision, scale);
+      case MySql.ID:
+      case MsSql.ID:
+        return String.format("DECIMAL (%s,%s)", precision, scale);
+      case H2.ID:
+        return "DOUBLE";
+      default:
+        throw new UnsupportedOperationException(String.format("Unknown dialect '%s'", dialect.getId()));
+    }
+  }
+
+  public static class Builder {
+    @CheckForNull
+    private String columnName;
+    private int precision = DEFAULT_PRECISION;
+    private int scale = DEFAULT_SACLE;
+    private boolean isNullable = false;
+
+    public Builder setColumnName(String columnName) {
+      this.columnName = validateColumnName(columnName);
+      return this;
+    }
+
+    public Builder setIsNullable(boolean isNullable) {
+      this.isNullable = isNullable;
+      return this;
+    }
+
+    public Builder setPrecision(int precision) {
+      this.precision = precision;
+      return this;
+    }
+
+    public Builder setScale(int scale) {
+      this.scale = scale;
+      return this;
+    }
+
+    public DecimalColumnDef build() {
+      validateColumnName(columnName);
+      return new DecimalColumnDef(this);
+    }
+  }
+
+}
index 4e1ea5cd8118ba8d4848a8cb2aaca70108dedb59..9f60c1336603b6f2aef03adb498bb61672058975 100644 (file)
@@ -52,6 +52,7 @@ import org.sonar.db.version.v52.FeedFileSourcesDataType;
 import org.sonar.db.version.v52.FeedManualMeasuresComponentUuid;
 import org.sonar.db.version.v52.FeedMetricsBooleans;
 import org.sonar.db.version.v52.FeedProjectLinksComponentUuid;
+import org.sonar.db.version.v52.IncreasePrecisionOfNumerics;
 import org.sonar.db.version.v52.MoveProjectProfileAssociation;
 import org.sonar.db.version.v52.RemoveComponentLibraries;
 import org.sonar.db.version.v52.RemoveDuplicatedComponentKeys;
@@ -103,6 +104,7 @@ public class MigrationStepModule extends Module {
       FeedManualMeasuresComponentUuid.class,
       RemoveSnapshotLibraries.class,
       RemoveComponentLibraries.class,
-      RemoveDuplicatedComponentKeys.class);
+      RemoveDuplicatedComponentKeys.class,
+      IncreasePrecisionOfNumerics.class);
   }
 }
diff --git a/sonar-db/src/main/java/org/sonar/db/version/v52/IncreasePrecisionOfNumerics.java b/sonar-db/src/main/java/org/sonar/db/version/v52/IncreasePrecisionOfNumerics.java
new file mode 100644 (file)
index 0000000..9c4ad3e
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+
+package org.sonar.db.version.v52;
+
+import java.sql.SQLException;
+import java.util.List;
+import org.sonar.db.Database;
+import org.sonar.db.version.AlterColumnsBuilder;
+import org.sonar.db.version.DdlChange;
+
+import static org.sonar.db.version.DecimalColumnDef.newDecimalColumnDefBuilder;
+
+/**
+ * Update numeric type from numeric(30,20) to numeric(38,20) :
+ * <ul>
+ *  <li>metrics.worst_value</li>
+ *  <li>metrics.best_value</li>
+ *  <li>project_measures.value</li>
+ *  <li>project_measures.variation_value_1</li>
+ *  <li>project_measures.variation_value_2</li>
+ *  <li>project_measures.variation_value_3</li>
+ *  <li>project_measures.variation_value_4</li>
+ *  <li>project_measures.variation_value_5</li>
+ *  <li>manual_measures.value</li>
+ * </ul>
+ *
+ * The goal is to be able to manage DATE (DATE is using 13 digits) in these columns
+ */
+public class IncreasePrecisionOfNumerics extends DdlChange {
+
+  public IncreasePrecisionOfNumerics(Database db) {
+    super(db);
+  }
+
+  @Override
+  public void execute(DdlChange.Context context) throws SQLException {
+    executeSql(context, "metrics", "worst_value", "best_value");
+    executeSql(context, "project_measures", "value", "variation_value_1", "variation_value_2", "variation_value_3", "variation_value_4", "variation_value_5");
+    executeSql(context, "manual_measures", "value");
+  }
+
+  private void executeSql(DdlChange.Context context, String table, String... columns) throws SQLException {
+    for (String sql : generateSql(table, columns)) {
+      context.execute(sql);
+    }
+  }
+
+  private List<String> generateSql(String table, String... columns) {
+    AlterColumnsBuilder columnsBuilder = new AlterColumnsBuilder(getDatabase().getDialect(), table);
+    for (String column : columns) {
+      columnsBuilder.updateColumn(newDecimalColumnDefBuilder().setColumnName(column).build());
+    }
+    return columnsBuilder.build();
+  }
+
+}
index 9a4170eaf70105d6f2093be3beda568cbd272304..d8b4310588dafbc2929ee22c395df512fffce36a 100644 (file)
@@ -346,9 +346,9 @@ INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('924');
 INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('925');
 INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('926');
 INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('927');
-INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('928');
 INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('929');
 INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('930');
+INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('931');
 
 INSERT INTO USERS(ID, LOGIN, NAME, EMAIL, CRYPTED_PASSWORD, SALT, CREATED_AT, UPDATED_AT, REMEMBER_TOKEN, REMEMBER_TOKEN_EXPIRES_AT) VALUES (1, 'admin', 'Administrator', '', 'a373a0e667abb2604c1fd571eb4ad47fe8cc0878', '48bc4b0d93179b5103fd3885ea9119498e9d161b', '1418215735482', '1418215735482', null, null);
 ALTER TABLE USERS ALTER COLUMN ID RESTART WITH 2;
diff --git a/sonar-db/src/test/java/org/sonar/db/version/AlterColumnsBuilderTest.java b/sonar-db/src/test/java/org/sonar/db/version/AlterColumnsBuilderTest.java
new file mode 100644 (file)
index 0000000..d801cc3
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * 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.
+ */
+
+package org.sonar.db.version;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+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.sonar.db.version.DecimalColumnDef.newDecimalColumnDefBuilder;
+import static org.sonar.db.version.StringColumnDef.newStringColumnDefBuilder;
+
+public class AlterColumnsBuilderTest {
+
+  @Rule
+  public ExpectedException thrown = ExpectedException.none();
+
+  static final String TABLE_NAME = "issues";
+
+  @Test
+  public void update_columns_on_h2() {
+    assertThat(createSampleBuilder(new H2()).build())
+      .containsOnly("ALTER TABLE issues ALTER COLUMN value DOUBLE", "ALTER TABLE issues ALTER COLUMN name VARCHAR (10)");
+  }
+
+  @Test
+  public void update_columns_on_mssql() {
+    assertThat(createSampleBuilder(new MsSql()).build())
+      .containsOnly("ALTER TABLE issues ALTER COLUMN value DECIMAL (30,20)", "ALTER TABLE issues ALTER COLUMN name VARCHAR (10)");
+  }
+
+  @Test
+  public void update_columns_on_postgres() {
+    assertThat(createSampleBuilder(new PostgreSql()).build())
+      .containsOnly("ALTER TABLE issues ALTER COLUMN value TYPE NUMERIC (30,20), ALTER COLUMN name TYPE VARCHAR (10)");
+  }
+
+  @Test
+  public void update_columns_on_mysql() {
+    assertThat(createSampleBuilder(new MySql()).build())
+      .containsOnly("ALTER TABLE issues MODIFY COLUMN value DECIMAL (30,20), MODIFY COLUMN name VARCHAR (10)");
+  }
+
+  @Test
+  public void update_columns_on_oracle() {
+    assertThat(createSampleBuilder(new Oracle()).build())
+      .containsOnly("ALTER TABLE issues MODIFY (value NUMERIC (30,20), name VARCHAR (10))");
+  }
+
+  @Test
+  public void fail_with_ISE_if_no_column() {
+    thrown.expect(IllegalStateException.class);
+    thrown.expectMessage("No column has been defined");
+
+    new AlterColumnsBuilder(new H2(), TABLE_NAME).build();
+  }
+
+  private AlterColumnsBuilder createSampleBuilder(Dialect dialect) {
+    return new AlterColumnsBuilder(dialect, TABLE_NAME)
+      .updateColumn(
+        newDecimalColumnDefBuilder()
+          .setColumnName("value")
+          .setPrecision(30)
+          .setScale(20)
+          .build())
+      .updateColumn(
+        newStringColumnDefBuilder()
+          .setColumnName("name")
+          .setLimit(10)
+          .build());
+  }
+
+}
diff --git a/sonar-db/src/test/java/org/sonar/db/version/DecimalColumnDefTest.java b/sonar-db/src/test/java/org/sonar/db/version/DecimalColumnDefTest.java
new file mode 100644 (file)
index 0000000..f54250e
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * 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.
+ */
+
+package org.sonar.db.version;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+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.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class DecimalColumnDefTest {
+
+  @Rule
+  public ExpectedException thrown = ExpectedException.none();
+
+  @Test
+  public void build_string_column_def() throws Exception {
+    DecimalColumnDef def = new DecimalColumnDef.Builder()
+      .setColumnName("issues")
+      .setPrecision(30)
+      .setScale(20)
+      .setIsNullable(true)
+      .build();
+
+    assertThat(def.getName()).isEqualTo("issues");
+    assertThat(def.getPrecision()).isEqualTo(30);
+    assertThat(def.getScale()).isEqualTo(20);
+    assertThat(def.isNullable()).isTrue();
+  }
+
+  @Test
+  public void fail_with_NPE_if_name_is_null() throws Exception {
+    thrown.expect(NullPointerException.class);
+    thrown.expectMessage("Column name cannot be null");
+
+    new DecimalColumnDef.Builder()
+      .setColumnName(null);
+  }
+
+  @Test
+  public void fail_with_NPE_if_no_name() throws Exception {
+    thrown.expect(NullPointerException.class);
+    thrown.expectMessage("Column name cannot be null");
+
+    new DecimalColumnDef.Builder()
+      .build();
+  }
+
+  @Test
+  public void default_precision_is_38() throws Exception {
+    DecimalColumnDef def = new DecimalColumnDef.Builder()
+      .setColumnName("issues")
+      .setScale(20)
+      .setIsNullable(true)
+      .build();
+
+    assertThat(def.getPrecision()).isEqualTo(38);
+  }
+
+  @Test
+  public void default_precision_is_20() throws Exception {
+    DecimalColumnDef def = new DecimalColumnDef.Builder()
+      .setColumnName("issues")
+      .setPrecision(30)
+      .setIsNullable(true)
+      .build();
+
+    assertThat(def.getScale()).isEqualTo(20);
+  }
+
+  @Test
+  public void create_builder_with_default_values() throws Exception {
+    DecimalColumnDef def = new DecimalColumnDef.Builder()
+      .setColumnName("issues")
+      .build();
+
+    assertThat(def.getPrecision()).isEqualTo(38);
+    assertThat(def.getScale()).isEqualTo(20);
+    assertThat(def.isNullable()).isFalse();
+  }
+
+  @Test
+  public void generate_sql_type() throws Exception {
+    DecimalColumnDef def = new DecimalColumnDef.Builder()
+      .setColumnName("issues")
+      .setPrecision(30)
+      .setScale(20)
+      .setIsNullable(true)
+      .build();
+
+    assertThat(def.generateSqlType(new H2())).isEqualTo("DOUBLE");
+    assertThat(def.generateSqlType(new PostgreSql())).isEqualTo("NUMERIC (30,20)");
+    assertThat(def.generateSqlType(new MsSql())).isEqualTo("DECIMAL (30,20)");
+    assertThat(def.generateSqlType(new MySql())).isEqualTo("DECIMAL (30,20)");
+    assertThat(def.generateSqlType(new Oracle())).isEqualTo("NUMERIC (30,20)");
+  }
+
+  @Test
+  public void fail_with_UOE_to_generate_sql_type_when_unknown_dialect() throws Exception {
+    thrown.expect(UnsupportedOperationException.class);
+    thrown.expectMessage("Unknown dialect 'unknown'");
+
+    DecimalColumnDef def = new DecimalColumnDef.Builder()
+      .setColumnName("issues")
+      .setPrecision(30)
+      .setScale(20)
+      .setIsNullable(true)
+      .build();
+
+    Dialect dialect = mock(Dialect.class);
+    when(dialect.getId()).thenReturn("unknown");
+    def.generateSqlType(dialect);
+  }
+
+}
index 6c3fb4cba2534a8a6e66f6ad6e27c8bd95b69223..933def517558cbfe6624a440c22f39d8ff9fc282 100644 (file)
@@ -21,7 +21,6 @@ package org.sonar.db.version;
 
 import org.junit.Test;
 import org.sonar.core.platform.ComponentContainer;
-import org.sonar.db.version.MigrationStepModule;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
@@ -30,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(38);
+    assertThat(container.size()).isEqualTo(39);
   }
 }
diff --git a/sonar-db/src/test/java/org/sonar/db/version/v52/IncreasePrecisionOfNumericsTest.java b/sonar-db/src/test/java/org/sonar/db/version/v52/IncreasePrecisionOfNumericsTest.java
new file mode 100644 (file)
index 0000000..6defc82
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+package org.sonar.db.version.v52;
+
+import org.junit.Test;
+import org.sonar.db.Database;
+import org.sonar.db.dialect.PostgreSql;
+import org.sonar.db.version.DdlChange;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+/**
+ * It's not possible to test the change of type to NUMERIC (38,20) with a H2 db because on H2 numeric type is a DOUBLE, without precision and scale.
+ * That's why mocks are used in this test.
+ */
+public class IncreasePrecisionOfNumericsTest {
+
+  DdlChange.Context context = mock(DdlChange.Context.class);
+  Database db = mock(Database.class);
+
+  IncreasePrecisionOfNumerics underTest = new IncreasePrecisionOfNumerics(db);
+
+  @Test
+  public void update_column_types() throws Exception {
+    when(db.getDialect()).thenReturn(new PostgreSql());
+
+    underTest.execute(context);
+
+    verify(context).execute("ALTER TABLE metrics ALTER COLUMN worst_value TYPE NUMERIC (38,20), ALTER COLUMN best_value TYPE NUMERIC (38,20)");
+    verify(context).execute("ALTER TABLE project_measures " +
+      "ALTER COLUMN value TYPE NUMERIC (38,20), " +
+      "ALTER COLUMN variation_value_1 TYPE NUMERIC (38,20), " +
+      "ALTER COLUMN variation_value_2 TYPE NUMERIC (38,20), " +
+      "ALTER COLUMN variation_value_3 TYPE NUMERIC (38,20), " +
+      "ALTER COLUMN variation_value_4 TYPE NUMERIC (38,20), " +
+      "ALTER COLUMN variation_value_5 TYPE NUMERIC (38,20)");
+    verify(context).execute("ALTER TABLE manual_measures ALTER COLUMN value TYPE NUMERIC (38,20)");
+  }
+
+}