]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-14323 Optimize DB migrations from 7.9 LTS to 8.X LTS
authorDuarte Meneses <duarte.meneses@sonarsource.com>
Thu, 7 Jan 2021 21:28:26 +0000 (15:28 -0600)
committersonartech <sonartech@sonarsource.com>
Mon, 8 Feb 2021 20:07:45 +0000 (20:07 +0000)
23 files changed:
server/sonar-db-core/src/main/java/org/sonar/db/DatabaseUtils.java
server/sonar-db-core/src/test/java/org/sonar/db/DatabaseUtilsTest.java
server/sonar-db-core/src/test/resources/org/sonar/db/DatabaseUtilsTest/sql.sql
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v84/DbVersion84.java
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v84/issuechanges/CopyIssueChangesTable.java
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v84/issuechanges/DropIssueChangesTable.java
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v85/AddPrimaryKeyOnUuidForIssueChangesTable.java
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v85/CreateTmpIssueChangesTable.java
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v85/DbVersion85.java
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v85/DropIssueChangesTable.java [new file with mode: 0644]
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v85/RenameTmpIssueChangesToIssueChanges.java
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v85/AddIndexOnIssueKeyForIssueChangesTableTest.java
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v85/AddIndexOnKeeForIssueChangesTableTest.java
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v85/AddIndexOnProjectUuidOnIssueChangesTableTest.java
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v85/AddPrimaryKeyOnUuidForIssueChangesTableTest.java
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v85/CreateTmpIssueChangesTableTest.java
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v85/DropIssueChangesTableTest.java [new file with mode: 0644]
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v85/MakeIssueKeyNotNullOnIssueChangesTableTest.java
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v85/MakeProjectUuidNotNullOnIssueChangesTableTest.java
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v85/MakeUuidNotNullOnIssueChangesTableTest.java
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v85/RenameTmpIssueChangesToIssueChangesTest.java
server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v84/issuechanges/CopyIssueChangesTableTest/schema.sql
server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v85/DropIssueChangesTableTest/schema.sql [new file with mode: 0644]

index 4f579f486f2564b95a7307f9baddb7bf40a23251..2d566ee3ede486d49e47a9c38010d0c7adeee5a0 100644 (file)
@@ -351,6 +351,30 @@ public class DatabaseUtils {
     }
   }
 
+  public static boolean tableColumnExists(Connection connection, String tableName, String columnName) {
+    try {
+      return columnExists(connection, tableName.toLowerCase(Locale.US), columnName)
+        || columnExists(connection, tableName.toUpperCase(Locale.US), columnName);
+    } catch (SQLException e) {
+      throw wrapSqlException(e, "Can not check that column %s exists", columnName);
+    }
+  }
+
+  private static boolean columnExists(Connection connection, String tableName, String columnName) throws SQLException {
+    String schema = getSchema(connection);
+    try (ResultSet rs = connection.getMetaData().getColumns(connection.getCatalog(), schema, tableName, null)) {
+      while (rs.next()) {
+        for (int i = 1; i <= rs.getMetaData().getColumnCount(); i++) {
+          String name = rs.getString(i);
+          if (columnName.equalsIgnoreCase(name)) {
+            return true;
+          }
+        }
+      }
+      return false;
+    }
+  }
+
   @CheckForNull
   private static String getSchema(Connection connection) {
     String schema = null;
index 92b20692e32186e90012fcd48d3fa5f290024db6..21ae0cbba432c6572507eda27ea08c7f44fc24a4 100644 (file)
@@ -85,6 +85,46 @@ public class DatabaseUtilsTest {
     }
   }
 
+  @Test
+  public void find_column_with_lower_case_table_name_and_upper_case_column_name() throws SQLException {
+    String tableName = "tablea";
+    String columnName = "COLUMNA";
+    try (Connection connection = dbTester.openConnection()) {
+      assertThat(DatabaseUtils.tableColumnExists(connection, tableName, columnName)).isTrue();
+      assertThat(DatabaseUtils.tableColumnExists(connection, tableName.toLowerCase(Locale.US), columnName)).isTrue();
+    }
+  }
+  @Test
+  public void find_column_with_upper_case_table_name_and_upper_case_column_name() throws SQLException {
+    String tableName = "TABLEA";
+    String columnName = "COLUMNA";
+    try (Connection connection = dbTester.openConnection()) {
+      assertThat(DatabaseUtils.tableColumnExists(connection, tableName, columnName)).isTrue();
+      assertThat(DatabaseUtils.tableColumnExists(connection, tableName.toLowerCase(Locale.US), columnName)).isTrue();
+    }
+  }
+
+  @Test
+  public void find_column_with_lower_case_table_name_and_lower_case_column_name() throws SQLException {
+    String tableName = "tablea";
+    String columnName = "columna";
+    try (Connection connection = dbTester.openConnection()) {
+      assertThat(DatabaseUtils.tableColumnExists(connection, tableName, columnName)).isTrue();
+      assertThat(DatabaseUtils.tableColumnExists(connection, tableName.toLowerCase(Locale.US), columnName)).isTrue();
+    }
+  }
+
+  @Test
+  public void find_column_with_upper_case_table_name_and_lower_case_column_name() throws SQLException {
+    String tableName = "TABLEA";
+    String columnName = "columna";
+    try (Connection connection = dbTester.openConnection()) {
+      assertThat(DatabaseUtils.tableColumnExists(connection, tableName, columnName)).isTrue();
+      assertThat(DatabaseUtils.tableColumnExists(connection, tableName, columnName.toLowerCase(Locale.US))).isTrue();
+      assertThat(DatabaseUtils.tableColumnExists(connection, tableName.toLowerCase(Locale.US), columnName.toLowerCase(Locale.US))).isTrue();
+    }
+  }
+
   @Test
   public void should_close_connection() throws Exception {
     try (Connection connection = dbTester.openConnection()) {
index ec4b8782e31872f2823f2cba000400859d883e37..e0fbf26800c0f20178e662db16c17698d30bebf1 100644 (file)
@@ -2,6 +2,10 @@ CREATE TABLE "schema_migrations" (
   "version" VARCHAR(256) NOT NULL
 );
 
+CREATE TABLE "TABLEA" (
+  "COLUMNA" VARCHAR(256) NOT NULL
+);
+
 CREATE INDEX UPPER_CASE_NAME ON schema_migrations (version);
 
 CREATE INDEX lower_case_name ON schema_migrations (version);
index 0e81cd6ac0d986bde3a144e61edbfe586ed6aa62..8e4a77256dafe9464d9af1ffb9281a76f080e1bd 100644 (file)
@@ -331,6 +331,7 @@ import org.sonar.server.platform.db.migration.version.v84.usertokens.DropIdColum
 import org.sonar.server.platform.db.migration.version.v84.usertokens.DropPrimaryKeyOnIdColumnOfUserTokensTable;
 import org.sonar.server.platform.db.migration.version.v84.usertokens.MakeUserTokensUuidNotNullable;
 import org.sonar.server.platform.db.migration.version.v84.usertokens.PopulateUserTokensUuid;
+import org.sonar.server.platform.db.migration.version.v85.AddIndexOnProjectUuidOnIssueChangesTable;
 
 public class DbVersion84 implements DbVersion {
   @Override
@@ -446,6 +447,7 @@ public class DbVersion84 implements DbVersion {
       .add(3479, "Add index on 'ISSUE_KEY' of 'ISSUE_CHANGES' table", AddIndexOnIssueKeyOfIssueChangesTable.class)
       .add(3480, "Add index on 'KEE' of 'ISSUE_CHANGES' table", AddIndexOnKeeOfIssueChangesTable.class)
       .add(3481, "Add primary key on 'UUID' column of 'ISSUE_CHANGES' table", AddPrimaryKeyOnUuidColumnOfIssueChangesTable.class)
+      .add(3482, "Add index on 'project_uuid' for table 'ISSUE_CHANGES'", AddIndexOnProjectUuidOnIssueChangesTable.class)
 
       // Migration of QUALITY_GATE_CONDITIONS table
       .add(3483, "Add 'UUID' column on 'QUALITY_GATE_CONDITIONS' table", AddUuidColumnToQualityGateConditionsTable.class)
@@ -782,7 +784,7 @@ public class DbVersion84 implements DbVersion {
       .add(3804, "Populate 'need_issue_sync' of 'project_branches'", PopulateProjectBranchesNeedIssueSync.class)
       .add(3805, "Make 'need_issue_sync' of 'project_branches' not null", MakeProjectBranchesNeedIssueSyncNonNull.class)
 
-      .add(3806, "Drop local webhooks", DropLocalWebhooks.class)  
+      .add(3806, "Drop local webhooks", DropLocalWebhooks.class)
 
       // Migration of ALM_SETTINGS table
       .add(3807, "Add columns 'CLIENT_ID' and 'CLIENT_SECRET' to 'ALM_SETTINGS' table", AddClientIdAndClientSecretColumns.class)
index 126e096bda2f12a05e408e1d4cf5ab2108704924..8f09a04aeb28c1f2a933d70800426bc35672af7c 100644 (file)
@@ -21,42 +21,61 @@ package org.sonar.server.platform.db.migration.version.v84.issuechanges;
 
 import java.sql.SQLException;
 import org.sonar.db.Database;
-import org.sonar.server.platform.db.migration.sql.CreateTableAsBuilder;
+import org.sonar.db.dialect.MsSql;
+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;
 
-import static org.sonar.server.platform.db.migration.def.BigIntegerColumnDef.newBigIntegerColumnDefBuilder;
-import static org.sonar.server.platform.db.migration.def.ClobColumnDef.newClobColumnDefBuilder;
 import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.newVarcharColumnDefBuilder;
 
 public class CopyIssueChangesTable extends DdlChange {
+  private static final String COPY_NAME = "issue_changes_copy";
+
   public CopyIssueChangesTable(Database db) {
     super(db);
   }
 
-  @Override public void execute(Context context) throws SQLException {
-    CreateTableAsBuilder builder = new CreateTableAsBuilder(getDialect(), "issue_changes_copy", "issue_changes")
-      // this will cause the following changes:
-      // * Add UUID with values in ID casted to varchar
-      .addColumnWithCast(newVarcharColumnDefBuilder().setColumnName("uuid").setLimit(40).setIsNullable(false).build(), "id")
-      .addColumn(newVarcharColumnDefBuilder().setColumnName("kee").setLimit(50).build())
-      .addColumn(newVarcharColumnDefBuilder().setColumnName("issue_key").setLimit(50).setIsNullable(false).build())
-      .addColumn(newVarcharColumnDefBuilder().setColumnName("user_login").setLimit(255).build())
-      .addColumn(newVarcharColumnDefBuilder().setColumnName("change_type").setLimit(20).build())
-      .addColumn(newClobColumnDefBuilder().setColumnName("change_data").build())
-      .addColumn(newBigIntegerColumnDefBuilder().setColumnName("created_at").build())
-      .addColumn(newBigIntegerColumnDefBuilder().setColumnName("updated_at").build())
-      .addColumn(newBigIntegerColumnDefBuilder().setColumnName("issue_change_creation_date").build());
-    context.execute(builder.build());
-       /*
-        "UUID VARCHAR(40) NOT NULL",
-        "KEE VARCHAR(50)",
-        "ISSUE_KEY VARCHAR(50) NOT NULL",
-        "USER_LOGIN VARCHAR(255)",
-        "CHANGE_TYPE VARCHAR(20)",
-        "CHANGE_DATA CLOB(2147483647)",
-        "CREATED_AT BIGINT",
-        "UPDATED_AT BIGINT",
-        "ISSUE_CHANGE_CREATION_DATE BIGINT"
-        */
+  @Override
+  public void execute(Context context) throws SQLException {
+
+    String query;
+    if (getDatabase().getDialect().getId().equals(MsSql.ID)) {
+      query = "select cast (ic.id AS VARCHAR(40)) AS uuid, ic.kee, ic.issue_key, ic.user_login, ic.change_type, " +
+        "ic.change_data, ic.created_at, ic.updated_at, ic.issue_change_creation_date, i.project_uuid " +
+        "INTO issue_changes_copy " +
+        "FROM issue_changes AS ic inner join issues i on i.kee = ic.issue_key";
+    } else {
+      query = "create table issue_changes_copy " +
+        "(uuid, kee, issue_key, user_login, change_type, change_data, created_at, updated_at, issue_change_creation_date, project_uuid)" +
+        "as (" +
+        "SELECT cast (ic.id AS VARCHAR(40)) AS uuid, ic.kee, ic.issue_key, ic.user_login, ic.change_type, ic.change_data, ic.created_at, ic.updated_at, "
+        + "ic.issue_change_creation_date, i.project_uuid " +
+        "FROM issue_changes ic " +
+        "inner join issues i on i.kee = ic.issue_key " +
+        ")";
+    }
+
+    context.execute(query);
+    context.execute(new AlterColumnsBuilder(getDialect(), COPY_NAME).updateColumn(
+      newVarcharColumnDefBuilder()
+        .setColumnName("project_uuid")
+        .setIsNullable(false)
+        .setDefaultValue(null)
+        .setLimit(VarcharColumnDef.UUID_VARCHAR_SIZE)
+        .build()).build());
+    context.execute(new AlterColumnsBuilder(getDialect(), COPY_NAME).updateColumn(
+      newVarcharColumnDefBuilder()
+        .setColumnName("issue_key")
+        .setIsNullable(false)
+        .setDefaultValue(null)
+        .setLimit(VarcharColumnDef.UUID_VARCHAR_SIZE)
+        .build()).build());
+    context.execute(new AlterColumnsBuilder(getDialect(), COPY_NAME).updateColumn(
+      newVarcharColumnDefBuilder()
+        .setColumnName("uuid")
+        .setIsNullable(false)
+        .setDefaultValue(null)
+        .setLimit(VarcharColumnDef.UUID_SIZE)
+        .build()).build());
   }
 }
index 19bbc774fe8d34ffaf85068d3a799c1757d8f2c7..7b6b1420934d3952609f09afda6c4845a2ef1013 100644 (file)
@@ -29,7 +29,8 @@ public class DropIssueChangesTable extends DdlChange {
     super(db);
   }
 
-  @Override public void execute(Context context) throws SQLException {
+  @Override
+  public void execute(Context context) throws SQLException {
     context.execute(new DropTableBuilder(getDialect(), "issue_changes").build());
   }
 }
index 648885623d13a3b0e2b3459f90da45bb0f80759d..37feefda2a8d65b07984bcfdb73c3df7e95d9f2b 100644 (file)
  */
 package org.sonar.server.platform.db.migration.version.v85;
 
+import java.sql.Connection;
 import java.sql.SQLException;
 import org.sonar.db.Database;
 import org.sonar.server.platform.db.migration.sql.AddPrimaryKeyBuilder;
+import org.sonar.db.DatabaseUtils;
 import org.sonar.server.platform.db.migration.step.DdlChange;
 
 public class AddPrimaryKeyOnUuidForIssueChangesTable extends DdlChange {
@@ -34,6 +36,10 @@ public class AddPrimaryKeyOnUuidForIssueChangesTable extends DdlChange {
 
   @Override
   public void execute(Context context) throws SQLException {
-    context.execute(new AddPrimaryKeyBuilder(TABLE, "uuid").build());
+    try (Connection connection = getDatabase().getDataSource().getConnection()) {
+      if (!DatabaseUtils.indexExistsIgnoreCase(TABLE, "issue_changes_project_uuid", connection)) {
+        context.execute(new AddPrimaryKeyBuilder(TABLE, "uuid").build());
+      }
+    }
   }
 }
index 415cf7ca4f0698d8809814dad556ac12d26ffc5e..6fd09ceaab26257ecdf662aa13efc6725da798ec 100644 (file)
  */
 package org.sonar.server.platform.db.migration.version.v85;
 
+import java.sql.Connection;
 import java.sql.SQLException;
 import org.sonar.db.Database;
+import org.sonar.db.DatabaseUtils;
 import org.sonar.db.dialect.MsSql;
 import org.sonar.server.platform.db.migration.step.DdlChange;
 
@@ -32,23 +34,28 @@ public class CreateTmpIssueChangesTable extends DdlChange {
 
   @Override
   public void execute(Context context) throws SQLException {
+    try (Connection connection = getDatabase().getDataSource().getConnection()) {
+      if (DatabaseUtils.tableColumnExists(connection, "issue_changes", "project_uuid")) {
+        // This migration might already have been done in v84 (#3476) if using SQ >= 8.7.
+        return;
+      }
+      String query;
+      if (getDatabase().getDialect().getId().equals(MsSql.ID)) {
+        query = "SELECT ic.uuid, ic.kee, ic.issue_key, ic.user_login, ic.change_type, " +
+          "ic.change_data, ic.created_at, ic.updated_at, ic.issue_change_creation_date, i.project_uuid " +
+          "INTO tmp_issue_changes " +
+          "FROM issue_changes AS ic inner join issues i on i.kee = ic.issue_key";
+      } else {
+        query = "create table tmp_issue_changes " +
+          "(uuid, kee, issue_key, user_login, change_type, change_data, created_at, updated_at, issue_change_creation_date, project_uuid)" +
+          "as (" +
+          "SELECT ic.uuid, ic.kee, ic.issue_key, ic.user_login, ic.change_type, ic.change_data, ic.created_at, ic.updated_at, ic.issue_change_creation_date, i.project_uuid " +
+          "FROM issue_changes ic " +
+          "inner join issues i on i.kee = ic.issue_key " +
+          ")";
+      }
 
-    String query;
-    if (getDatabase().getDialect().getId().equals(MsSql.ID)) {
-      query = "SELECT ic.uuid, ic.kee, ic.issue_key, ic.user_login, ic.change_type, " +
-        "ic.change_data, ic.created_at, ic.updated_at, ic.issue_change_creation_date, i.project_uuid " +
-        "INTO tmp_issue_changes " +
-        "FROM issue_changes AS ic inner join issues i on i.kee = ic.issue_key";
-    } else {
-      query = "create table tmp_issue_changes " +
-        "(uuid, kee, issue_key, user_login, change_type, change_data, created_at, updated_at, issue_change_creation_date, project_uuid)" +
-        "as (" +
-        "SELECT ic.uuid, ic.kee, ic.issue_key, ic.user_login, ic.change_type, ic.change_data, ic.created_at, ic.updated_at, ic.issue_change_creation_date, i.project_uuid " +
-        "FROM issue_changes ic " +
-        "inner join issues i on i.kee = ic.issue_key " +
-        ")";
+      context.execute(query);
     }
-
-    context.execute(query);
   }
 }
index 81edee1886abca2491799b2cb5a2a2689e392a2d..01fcb2a77a0cdc2cd6204500cebca7314a8d4ea1 100644 (file)
@@ -21,7 +21,6 @@ package org.sonar.server.platform.db.migration.version.v85;
 
 import org.sonar.server.platform.db.migration.step.MigrationStepRegistry;
 import org.sonar.server.platform.db.migration.version.DbVersion;
-import org.sonar.server.platform.db.migration.version.v84.issuechanges.DropIssueChangesTable;
 
 public class DbVersion85 implements DbVersion {
 
@@ -34,6 +33,7 @@ public class DbVersion85 implements DbVersion {
       .add(4003, "Drop unused variation values columns in 'project_measures' table", DropUnusedVariationsInProjectMeasures.class)
       .add(4004, "Drop unused periods in 'snapshots' table", DropUnusedPeriodsInSnapshots.class)
       .add(4005, "Drop orphan favorites from 'properties' table", DropOrphanFavoritesFromProperties.class)
+
       .add(4006, "create 'tmp_issue_changes' table", CreateTmpIssueChangesTable.class)
       .add(4007, "drop 'issue_changes' table", DropIssueChangesTable.class)
       .add(4008, "rename 'tmp_issue_changes' table to 'issue_changes'", RenameTmpIssueChangesToIssueChanges.class)
@@ -44,6 +44,7 @@ public class DbVersion85 implements DbVersion {
       .add(4013, "add index on 'issue_key' for table 'issue_changes'", AddIndexOnIssueKeyForIssueChangesTable.class)
       .add(4014, "add index on 'kee' for table 'issue_changes'", AddIndexOnKeeForIssueChangesTable.class)
       .add(4015, "add index on 'project_uuid' for table 'issue_changes'", AddIndexOnProjectUuidOnIssueChangesTable.class)
+
       .add(4016, "Add 'type' column to 'plugins' table", AddTypeToPlugins.class)
       .add(4017, "Populate 'type' column in 'plugins' table", PopulateTypeInPlugins.class)
       .add(4018, "Alter 'type' column in 'plugins' to not nullable", AlterTypeInPluginNotNullable.class)
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v85/DropIssueChangesTable.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v85/DropIssueChangesTable.java
new file mode 100644 (file)
index 0000000..22aab06
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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.v85;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import org.sonar.db.Database;
+import org.sonar.db.DatabaseUtils;
+import org.sonar.server.platform.db.migration.sql.DropTableBuilder;
+import org.sonar.server.platform.db.migration.step.DdlChange;
+
+public class DropIssueChangesTable extends DdlChange {
+  public DropIssueChangesTable(Database db) {
+    super(db);
+  }
+
+  @Override
+  public void execute(Context context) throws SQLException {
+    try (Connection connection = getDatabase().getDataSource().getConnection()) {
+      if (DatabaseUtils.tableExists("tmp_issue_changes", connection)) {
+        context.execute(new DropTableBuilder(getDialect(), "issue_changes").build());
+      }
+    }
+  }
+}
index 0ed5b022131ed1e5d3557b5685894599138f52ef..2800416a523fea81e19ffa465080a25928ec2708 100644 (file)
  */
 package org.sonar.server.platform.db.migration.version.v85;
 
+import java.sql.Connection;
 import java.sql.SQLException;
 import org.sonar.db.Database;
+import org.sonar.db.DatabaseUtils;
 import org.sonar.server.platform.db.migration.sql.RenameTableBuilder;
 import org.sonar.server.platform.db.migration.step.DdlChange;
 
@@ -32,9 +34,13 @@ public class RenameTmpIssueChangesToIssueChanges extends DdlChange {
 
   @Override
   public void execute(Context context) throws SQLException {
-    context.execute(new RenameTableBuilder(getDialect())
-      .setName("tmp_issue_changes").setNewName("issue_changes")
-      .setAutoGeneratedId(false)
-      .build());
+    try (Connection connection = getDatabase().getDataSource().getConnection()) {
+      if (DatabaseUtils.tableExists("tmp_issue_changes", connection)) {
+        context.execute(new RenameTableBuilder(getDialect())
+          .setName("tmp_issue_changes").setNewName("issue_changes")
+          .setAutoGeneratedId(false)
+          .build());
+      }
+    }
   }
 }
index aeaeca3cb56c5f08618dcacc2a40d8dea73ed5cd..7337bb06dd62ab127d1afeb8695a338f3bdbf1cb 100644 (file)
@@ -39,4 +39,11 @@ public class AddIndexOnIssueKeyForIssueChangesTableTest {
     underTest.execute();
     db.assertIndex(TABLE_NAME, INDEX_NAME, "issue_key");
   }
+
+  @Test
+  public void migration_is_reentrant() throws SQLException {
+    underTest.execute();
+    underTest.execute();
+    db.assertIndex(TABLE_NAME, INDEX_NAME, "issue_key");
+  }
 }
index 8b7c7e2d31f3eac06d9d304def8aa49b820ac183..f4ebe62acbecba7b26f5248e5dd5250351a66635 100644 (file)
@@ -39,4 +39,11 @@ public class AddIndexOnKeeForIssueChangesTableTest {
     underTest.execute();
     db.assertIndex(TABLE_NAME, INDEX_NAME, "kee");
   }
+
+  @Test
+  public void migration_is_reentrant() throws SQLException {
+    underTest.execute();
+    underTest.execute();
+    db.assertIndex(TABLE_NAME, INDEX_NAME, "kee");
+  }
 }
index 2e32cf3b1c2642618c87d2d4d2c9595792a5af30..e47019251dcadb881bc1f8b54d920a6eaa24523d 100644 (file)
@@ -40,4 +40,11 @@ public class AddIndexOnProjectUuidOnIssueChangesTableTest {
     db.assertIndex(TABLE_NAME, INDEX_NAME, "project_uuid");
   }
 
+  @Test
+  public void migration_is_reentrant() throws SQLException {
+    underTest.execute();
+    underTest.execute();
+    db.assertIndex(TABLE_NAME, INDEX_NAME, "project_uuid");
+  }
+
 }
index d3d0b85e00a94b1d37dccf43985901ff869b6c57..25f8681a9abc66c61e9ca0997c0bf0e23bdc77f4 100644 (file)
@@ -41,6 +41,15 @@ public class AddPrimaryKeyOnUuidForIssueChangesTableTest {
     db.assertPrimaryKey("issue_changes", "pk_issue_changes", "uuid");
   }
 
+  @Test
+  public void skip_if_project_uuid_index_exists() throws SQLException {
+    db.executeDdl("create index issue_changes_project_uuid on issue_changes ( issue_key)");
+
+    underTest.execute();
+
+    db.assertNoPrimaryKey("issue_changes");
+  }
+
   @Test
   public void migration_is_not_re_entrant() throws SQLException {
     underTest.execute();
index 25fc79ad719400b610fd34f1df79042001728462..96267985c853c7118f6af23cabb3590a2b6285f6 100644 (file)
@@ -41,6 +41,14 @@ public class CreateTmpIssueChangesTableTest {
 
   private CreateTmpIssueChangesTable underTest = new CreateTmpIssueChangesTable(dbTester.database());
 
+  @Test
+  public void skip_if_project_uuid_column_exists() throws SQLException {
+    dbTester.executeDdl("ALTER TABLE issue_changes ADD project_uuid VARCHAR");
+
+    underTest.execute();
+    dbTester.assertTableDoesNotExist(TABLE_NAME);
+  }
+
   @Test
   public void table_has_been_created() throws SQLException {
     underTest.execute();
diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v85/DropIssueChangesTableTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v85/DropIssueChangesTableTest.java
new file mode 100644 (file)
index 0000000..73ad587
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2021 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.v85;
+
+import java.sql.SQLException;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.db.CoreDbTester;
+import org.sonar.server.platform.db.migration.step.MigrationStep;
+
+public class DropIssueChangesTableTest {
+  @Rule
+  public CoreDbTester db = CoreDbTester.createForSchema(DropIssueChangesTableTest.class, "schema.sql");
+
+  private MigrationStep underTest = new DropIssueChangesTable(db.database());
+
+  @Test
+  public void dont_drop_if_tmp_table_doesnt_exist() throws SQLException {
+    db.executeDdl("drop table tmp_issue_changes");
+    underTest.execute();
+    db.assertTableExists("issue_changes");
+  }
+
+  @Test
+  public void execute() throws SQLException {
+    db.assertTableExists("issue_changes");
+    underTest.execute();
+    db.assertTableDoesNotExist("issue_changes");
+  }
+
+  @Test
+  public void migration_is_re_entrant() throws SQLException {
+    db.assertTableExists("issue_changes");
+
+    underTest.execute();
+
+    // re-entrant
+    underTest.execute();
+    db.assertTableDoesNotExist("issue_changes");
+  }
+}
index 7aee044b6a9bec9733e66b4f53525bd228588c1b..ca4bb48285b5d3f69a6ee9b22bbbd50e21dcb3f6 100644 (file)
@@ -41,4 +41,11 @@ public class MakeIssueKeyNotNullOnIssueChangesTableTest {
     db.assertColumnDefinition("issue_changes", "issue_key", VARCHAR, 50, false);
   }
 
+  @Test
+  public void migration_is_reentrant() throws SQLException {
+    underTest.execute();
+    underTest.execute();
+
+    db.assertColumnDefinition("issue_changes", "issue_key", VARCHAR, 50, false);
+  }
 }
index de962d7cb9b41ae7f1dbb4b7986e6d477c5d7a7e..84b9170e80f32cfeaa99ff300115d5fb27355da3 100644 (file)
@@ -40,4 +40,12 @@ public class MakeProjectUuidNotNullOnIssueChangesTableTest {
 
     db.assertColumnDefinition("issue_changes", "project_uuid", VARCHAR, 50, false);
   }
+
+  @Test
+  public void migration_is_reentrant() throws SQLException {
+    underTest.execute();
+    underTest.execute();
+
+    db.assertColumnDefinition("issue_changes", "project_uuid", VARCHAR, 50, false);
+  }
 }
index 1c843e71d87b9a2ea2e43aa0882151d67813f950..0e8af215179972802bbcc0f0e96593cb7caf4d38 100644 (file)
@@ -41,4 +41,12 @@ public class MakeUuidNotNullOnIssueChangesTableTest {
     db.assertColumnDefinition("issue_changes", "uuid", VARCHAR, 40, false);
   }
 
+  @Test
+  public void migration_is_reentrant() throws SQLException {
+    underTest.execute();
+    underTest.execute();
+
+    db.assertColumnDefinition("issue_changes", "uuid", VARCHAR, 40, false);
+  }
+
 }
index 462e12f01c41c9bb3e6734e233e7ee02593d50f7..bd9e206d468d6bd5e8ac832f8f28f94aa3115605 100644 (file)
@@ -38,6 +38,15 @@ public class RenameTmpIssueChangesToIssueChangesTest {
 
   private final RenameTmpIssueChangesToIssueChanges underTest = new RenameTmpIssueChangesToIssueChanges(dbTester.database());
 
+  @Test
+  public void only_rename_if_tmp_table_exists() throws SQLException {
+    dbTester.executeDdl("drop table " + OLD_TABLE_NAME);
+    underTest.execute();
+
+    dbTester.assertTableDoesNotExist(OLD_TABLE_NAME);
+    dbTester.assertTableDoesNotExist(NEW_TABLE_NAME);
+  }
+
   @Test
   public void table_has_been_renamed() throws SQLException {
     underTest.execute();
index 8b3247ab3965da13756afe2106387b91cb6e0dda..7854927f3049aed55796d54614f8d641d9b513b1 100644 (file)
@@ -11,3 +11,42 @@ CREATE TABLE "ISSUE_CHANGES"(
 );
 CREATE INDEX "ISSUE_CHANGES_ISSUE_KEY" ON "ISSUE_CHANGES"("ISSUE_KEY");
 CREATE INDEX "ISSUE_CHANGES_KEE" ON "ISSUE_CHANGES"("KEE");
+
+CREATE TABLE "ISSUES"(
+    "KEE" VARCHAR(50) NOT NULL,
+    "RULE_UUID" VARCHAR(40),
+    "SEVERITY" VARCHAR(10),
+    "MANUAL_SEVERITY" BOOLEAN NOT NULL,
+    "MESSAGE" VARCHAR(4000),
+    "LINE" INTEGER,
+    "GAP" DOUBLE,
+    "STATUS" VARCHAR(20),
+    "RESOLUTION" VARCHAR(20),
+    "CHECKSUM" VARCHAR(1000),
+    "REPORTER" VARCHAR(255),
+    "ASSIGNEE" VARCHAR(255),
+    "AUTHOR_LOGIN" VARCHAR(255),
+    "ACTION_PLAN_KEY" VARCHAR(50),
+    "ISSUE_ATTRIBUTES" VARCHAR(4000),
+    "EFFORT" INTEGER,
+    "CREATED_AT" BIGINT,
+    "UPDATED_AT" BIGINT,
+    "ISSUE_CREATION_DATE" BIGINT,
+    "ISSUE_UPDATE_DATE" BIGINT,
+    "ISSUE_CLOSE_DATE" BIGINT,
+    "TAGS" VARCHAR(4000),
+    "COMPONENT_UUID" VARCHAR(50),
+    "PROJECT_UUID" VARCHAR(50),
+    "LOCATIONS" BLOB,
+    "ISSUE_TYPE" TINYINT,
+    "FROM_HOTSPOT" BOOLEAN
+);
+ALTER TABLE "ISSUES" ADD CONSTRAINT "PK_ISSUES" PRIMARY KEY("KEE");
+CREATE INDEX "ISSUES_ASSIGNEE" ON "ISSUES"("ASSIGNEE");
+CREATE INDEX "ISSUES_COMPONENT_UUID" ON "ISSUES"("COMPONENT_UUID");
+CREATE INDEX "ISSUES_CREATION_DATE" ON "ISSUES"("ISSUE_CREATION_DATE");
+CREATE UNIQUE INDEX "ISSUES_KEE" ON "ISSUES"("KEE");
+CREATE INDEX "ISSUES_PROJECT_UUID" ON "ISSUES"("PROJECT_UUID");
+CREATE INDEX "ISSUES_RESOLUTION" ON "ISSUES"("RESOLUTION");
+CREATE INDEX "ISSUES_UPDATED_AT" ON "ISSUES"("UPDATED_AT");
+CREATE INDEX "ISSUES_RULE_UUID" ON "ISSUES"("RULE_UUID");
diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v85/DropIssueChangesTableTest/schema.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v85/DropIssueChangesTableTest/schema.sql
new file mode 100644 (file)
index 0000000..f39bedb
--- /dev/null
@@ -0,0 +1,39 @@
+CREATE TABLE "ISSUE_CHANGES"(
+    "ID" BIGINT NOT NULL AUTO_INCREMENT (1,1),
+    "KEE" VARCHAR(50),
+    "ISSUE_KEY" VARCHAR(50) NOT NULL,
+    "USER_LOGIN" VARCHAR(255),
+    "CHANGE_TYPE" VARCHAR(20),
+    "CHANGE_DATA" CLOB(2147483647),
+    "CREATED_AT" BIGINT,
+    "UPDATED_AT" BIGINT,
+    "ISSUE_CHANGE_CREATION_DATE" BIGINT
+);
+CREATE INDEX "ISSUE_CHANGES_ISSUE_KEY" ON "ISSUE_CHANGES"("ISSUE_KEY");
+CREATE INDEX "ISSUE_CHANGES_KEE" ON "ISSUE_CHANGES"("KEE");
+
+CREATE TABLE "TMP_ISSUE_CHANGES"(
+    "UUID" VARCHAR(40),
+    "KEE" VARCHAR(50),
+    "ISSUE_KEY" VARCHAR(50),
+    "USER_LOGIN" VARCHAR(255),
+    "CHANGE_TYPE" VARCHAR(20),
+    "CHANGE_DATA" CLOB(2147483647),
+    "CREATED_AT" BIGINT,
+    "UPDATED_AT" BIGINT,
+    "PROJECT_UUID" VARCHAR(50),
+    "ISSUE_CHANGE_CREATION_DATE" BIGINT
+);
+
+CREATE TABLE "ISSUE_CHANGES_COPY"(
+    "UUID" VARCHAR(40) NOT NULL,
+    "KEE" VARCHAR(50),
+    "ISSUE_KEY" VARCHAR(50) NOT NULL,
+    "USER_LOGIN" VARCHAR(255),
+    "CHANGE_TYPE" VARCHAR(20),
+    "CHANGE_DATA" CLOB(2147483647),
+    "CREATED_AT" BIGINT,
+    "UPDATED_AT" BIGINT,
+    "ISSUE_CHANGE_CREATION_DATE" BIGINT
+);
+