diff options
author | Sébastien Lesaint <sebastien.lesaint@sonarsource.com> | 2018-09-26 08:58:59 +0200 |
---|---|---|
committer | SonarTech <sonartech@sonarsource.com> | 2018-10-04 20:20:56 +0200 |
commit | 2c540713f9289d8cfd14a65f3b4c3c33a4696e20 (patch) | |
tree | 6f880db9407f37ccaf479cc79a8bf1c777a92b15 /server/sonar-db-migration/src | |
parent | e80c0f3d1e5cd459f88b7e0c41a2d9a7519e260f (diff) | |
download | sonarqube-2c540713f9289d8cfd14a65f3b4c3c33a4696e20.tar.gz sonarqube-2c540713f9289d8cfd14a65f3b4c3c33a4696e20.zip |
SONAR-11310 add temporary columns to CE tables
- add main_component_uuid temporary columns to CE_QUEUE
- add main_last_key and main_component_uuid columns to CE_ACTIVITY
- back to initial paradigm in Compute Engine: even for branches/PRs, the row in table PROJECTS a task belongs to is created in api/ce/submit
- add main component concept to CeTask
- improved consistency check when processing a report task to account for row in PROJECTS now being the one of the branche/PR
- stronger validation of characteristics passed to api/ce/submit
- add api/system/migrate_data for SonarCloud online data migration
Diffstat (limited to 'server/sonar-db-migration/src')
22 files changed, 1648 insertions, 1 deletions
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v74/AddTmpColumnsToCeActivity.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v74/AddTmpColumnsToCeActivity.java new file mode 100644 index 00000000000..f394c338378 --- /dev/null +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v74/AddTmpColumnsToCeActivity.java @@ -0,0 +1,31 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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.v74; + +import org.sonar.db.Database; +import org.sonar.server.platform.db.migration.SupportsBlueGreen; + +@SupportsBlueGreen +public class AddTmpColumnsToCeActivity extends AddTmpColumnsToCeTable { + + public AddTmpColumnsToCeActivity(Database db) { + super(db, "ce_activity"); + } +} diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v74/AddTmpColumnsToCeQueue.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v74/AddTmpColumnsToCeQueue.java new file mode 100644 index 00000000000..0cb136643b2 --- /dev/null +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v74/AddTmpColumnsToCeQueue.java @@ -0,0 +1,31 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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.v74; + +import org.sonar.db.Database; +import org.sonar.server.platform.db.migration.SupportsBlueGreen; + +@SupportsBlueGreen +public class AddTmpColumnsToCeQueue extends AddTmpColumnsToCeTable { + + public AddTmpColumnsToCeQueue(Database db) { + super(db, "ce_queue"); + } +} diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v74/AddTmpColumnsToCeTable.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v74/AddTmpColumnsToCeTable.java new file mode 100644 index 00000000000..3a2581897d0 --- /dev/null +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v74/AddTmpColumnsToCeTable.java @@ -0,0 +1,70 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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.v74; + +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.AddColumnsBuilder; +import org.sonar.server.platform.db.migration.sql.CreateIndexBuilder; +import org.sonar.server.platform.db.migration.step.DdlChange; + +import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.newVarcharColumnDefBuilder; + +abstract class AddTmpColumnsToCeTable extends DdlChange { + private static final VarcharColumnDef COLUMN_TMP_COMPONENT_UUID = newVarcharColumnDefBuilder() + .setColumnName("tmp_component_uuid") + .setLimit(VarcharColumnDef.UUID_SIZE) + .setIsNullable(true) + .build(); + private static final VarcharColumnDef COLUMN_TMP_MAIN_COMPONENT_UUID = newVarcharColumnDefBuilder() + .setColumnName("tmp_main_component_uuid") + .setLimit(VarcharColumnDef.UUID_SIZE) + .setIsNullable(true) + .build(); + private final String tableName; + + public AddTmpColumnsToCeTable(Database db, String tableName) { + super(db); + this.tableName = tableName; + } + + @Override + public void execute(Context context) throws SQLException { + context.execute(new AddColumnsBuilder(getDialect(), tableName) + .addColumn(COLUMN_TMP_MAIN_COMPONENT_UUID) + .addColumn(COLUMN_TMP_COMPONENT_UUID) + .build()); + + // create indexes + context.execute(new CreateIndexBuilder(getDialect()) + .setTable(tableName) + .setName(tableName + "_tmp_cpnt_uuid") + .addColumn(COLUMN_TMP_COMPONENT_UUID) + .setUnique(false) + .build()); + context.execute(new CreateIndexBuilder(getDialect()) + .setTable(tableName) + .setName(tableName + "_tmp_main_cpnt_uuid") + .addColumn(COLUMN_TMP_MAIN_COMPONENT_UUID) + .setUnique(false) + .build()); + } +} diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v74/AddTmpLastKeyColumnsToCeActivity.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v74/AddTmpLastKeyColumnsToCeActivity.java new file mode 100644 index 00000000000..63980918339 --- /dev/null +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v74/AddTmpLastKeyColumnsToCeActivity.java @@ -0,0 +1,105 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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.v74; + +import java.sql.SQLException; +import org.sonar.db.Database; +import org.sonar.server.platform.db.migration.SupportsBlueGreen; +import org.sonar.server.platform.db.migration.def.BooleanColumnDef; +import org.sonar.server.platform.db.migration.def.VarcharColumnDef; +import org.sonar.server.platform.db.migration.sql.AddColumnsBuilder; +import org.sonar.server.platform.db.migration.sql.CreateIndexBuilder; +import org.sonar.server.platform.db.migration.step.DdlChange; + +import static org.sonar.server.platform.db.migration.def.BooleanColumnDef.newBooleanColumnDefBuilder; +import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.UUID_SIZE; +import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.newVarcharColumnDefBuilder; + +@SupportsBlueGreen +public class AddTmpLastKeyColumnsToCeActivity extends DdlChange { + private static final String TABLE_NAME = "ce_activity"; + private static final int TASK_TYPE_COLUMN_SIZE = 15; + private static final BooleanColumnDef COLUMN_TMP_IS_LAST = newBooleanColumnDefBuilder() + .setColumnName("tmp_is_last") + .setIsNullable(true) + .build(); + private static final VarcharColumnDef COLUMN_TMP_IS_LAST_KEY = newVarcharColumnDefBuilder() + .setColumnName("tmp_is_last_key") + .setLimit(UUID_SIZE + TASK_TYPE_COLUMN_SIZE) + .setIsNullable(true) + .build(); + private static final BooleanColumnDef COLUMN_TMP_MAIN_IS_LAST = newBooleanColumnDefBuilder() + .setColumnName("tmp_main_is_last") + .setIsNullable(true) + .build(); + private static final VarcharColumnDef COLUMN_TMP_MAIN_IS_LAST_KEY = newVarcharColumnDefBuilder() + .setColumnName("tmp_main_is_last_key") + .setLimit(UUID_SIZE + TASK_TYPE_COLUMN_SIZE) + .setIsNullable(true) + .build(); + private static final VarcharColumnDef COLUMN_STATUS = newVarcharColumnDefBuilder() + .setColumnName("status") + .setLimit(15) + .setIsNullable(false) + .build(); + + public AddTmpLastKeyColumnsToCeActivity(Database db) { + super(db); + } + + @Override + public void execute(Context context) throws SQLException { + context.execute(new AddColumnsBuilder(getDialect(), TABLE_NAME) + .addColumn(COLUMN_TMP_IS_LAST) + .addColumn(COLUMN_TMP_IS_LAST_KEY) + .addColumn(COLUMN_TMP_MAIN_IS_LAST) + .addColumn(COLUMN_TMP_MAIN_IS_LAST_KEY) + .build()); + + // create indexes + context.execute(new CreateIndexBuilder(getDialect()) + .setTable(TABLE_NAME) + .setName(TABLE_NAME + "_t_islast_key") + .addColumn(COLUMN_TMP_IS_LAST_KEY) + .setUnique(false) + .build()); + context.execute(new CreateIndexBuilder(getDialect()) + .setTable(TABLE_NAME) + .setName(TABLE_NAME + "_t_islast") + .addColumn(COLUMN_TMP_IS_LAST) + .addColumn(COLUMN_STATUS) + .setUnique(false) + .build()); + context.execute(new CreateIndexBuilder(getDialect()) + .setTable(TABLE_NAME) + .setName(TABLE_NAME + "_t_main_islast_key") + .addColumn(COLUMN_TMP_MAIN_IS_LAST_KEY) + .setUnique(false) + .build()); + context.execute(new CreateIndexBuilder(getDialect()) + .setTable(TABLE_NAME) + .setName(TABLE_NAME + "_t_main_islast") + .addColumn(COLUMN_TMP_MAIN_IS_LAST) + .addColumn(COLUMN_STATUS) + .setUnique(false) + .build()); + + } +} diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v74/DbVersion74.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v74/DbVersion74.java index 4d45e1d0765..82b34413d0b 100644 --- a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v74/DbVersion74.java +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v74/DbVersion74.java @@ -32,6 +32,12 @@ public class DbVersion74 implements DbVersion { .add(2302, "Populate IS_AD_HOC in RULES", PopulateIsAdHocOnRules.class) .add(2303, "Set IS_EXTERNAL and IS_AD_HOC not nullable in RULES", SetIsExternalAndIsAdHocNotNullableInRules.class) .add(2304, "Add ad hoc related columns in RULES_METADATA", AddAdHocColumnsInInRulesMetadata.class) + .add(2305, "Add CE_QUEUE.MAIN_COMPONENT_UUID 1/5", AddTmpColumnsToCeQueue.class) + .add(2306, "Add CE_ACTIVITY.MAIN_COMPONENT_UUID 1/5", AddTmpColumnsToCeActivity.class) + .add(2307, "Populate CE_QUEUE.MAIN_COMPONENT_UUID 2/5", PopulateTmpColumnsToCeQueue.class) + .add(2308, "Populate CE_ACTIVITY.MAIN_COMPONENT_UUID 2/5", PopulateTmpColumnsToCeActivity.class) + .add(2309, "Add CE_ACTIVITY.MAIN_LAST_KEY 1/6", AddTmpLastKeyColumnsToCeActivity.class) + .add(2310, "Populate CE_ACTIVITY.MAIN_LAST_KEY 2/6", PopulateTmpLastKeyColumnsToCeActivity.class) ; } } diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v74/PopulateTmpColumnsToCeActivity.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v74/PopulateTmpColumnsToCeActivity.java new file mode 100644 index 00000000000..bcf08d5981e --- /dev/null +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v74/PopulateTmpColumnsToCeActivity.java @@ -0,0 +1,104 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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.v74; + +import java.sql.SQLException; +import org.sonar.api.config.Configuration; +import org.sonar.db.Database; +import org.sonar.server.platform.db.migration.SupportsBlueGreen; +import org.sonar.server.platform.db.migration.step.DataChange; +import org.sonar.server.platform.db.migration.step.MassUpdate; +import org.sonar.server.platform.db.migration.step.Select; +import org.sonar.server.platform.db.migration.step.SqlStatement; + +@SupportsBlueGreen +public class PopulateTmpColumnsToCeActivity extends DataChange { + private final Configuration configuration; + + public PopulateTmpColumnsToCeActivity(Database db, Configuration configuration) { + super(db); + this.configuration = configuration; + } + + @Override + protected void execute(Context context) throws SQLException { + if (configuration.getBoolean("sonar.sonarcloud.enabled").orElse(false)) { + // data migration will be done in background so that interruption of service + // is reduced during upgrade + return; + } + + // activity of long and short branches + populateCeActivityTmpColumns(context, "Archived tasks of branches", + "select" + + " cea.uuid, p.uuid, cea.component_uuid" + + " from ce_activity cea" + + " inner join projects mp on mp.uuid = cea.component_uuid" + + " inner join ce_task_characteristics ctc1 on ctc1.task_uuid = cea.uuid and ctc1.kee = 'branchType'" + + " inner join ce_task_characteristics ctc2 on ctc2.task_uuid = cea.uuid and ctc2.kee = 'branch'" + + " inner join projects p on p.kee = concat(mp.kee, ':BRANCH:', ctc2.text_value)" + + " where" + + " cea.component_uuid is not null" + + " and (cea.tmp_component_uuid is null or cea.tmp_main_component_uuid is null)"); + + // activity of PRs + populateCeActivityTmpColumns(context, "Archived tasks of PRs", + "select" + + " cea.uuid, p.uuid, cea.component_uuid" + + " from ce_activity cea" + + " inner join projects mp on mp.uuid = cea.component_uuid " + + " inner join ce_task_characteristics ctc1 on ctc1.task_uuid = cea.uuid and ctc1.kee = 'pullRequest'" + + " inner join projects p on p.kee = concat(mp.kee, ':PULL_REQUEST:', ctc1.text_value)" + + " where" + + " cea.component_uuid is not null" + + " and (cea.tmp_component_uuid is null or cea.tmp_main_component_uuid is null)"); + + // all activities which tmp columns are not populated yet (will include main and deprecated branches) + // both tmp columns will be set to CE_ACTIVITY.COMPONENT_UUID + // do not join on PROJECTS to also catch orphans + populateCeActivityTmpColumns(context, "Archived tasks of main and deprecated branches", + "select" + + " cea.uuid, cea.component_uuid, cea.component_uuid" + + " from ce_activity cea" + + " where" + + " cea.component_uuid is not null" + + " and (cea.tmp_component_uuid is null or cea.tmp_main_component_uuid is null)"); + } + + private static void populateCeActivityTmpColumns(Context context, String rowPluralName, String sql) throws SQLException { + MassUpdate massUpdate = context.prepareMassUpdate(); + massUpdate.select(sql); + massUpdate.update("update ce_activity set tmp_component_uuid=?, tmp_main_component_uuid=? where uuid=?"); + massUpdate.rowPluralName(rowPluralName); + massUpdate.execute(PopulateTmpColumnsToCeActivity::handleUpdate); + } + + private static boolean handleUpdate(Select.Row row, SqlStatement update) throws SQLException { + String uuid = row.getString(1); + String componentUuuid = row.getString(2); + String mainComponentUuuid = row.getString(3); + + update.setString(1, componentUuuid); + update.setString(2, mainComponentUuuid); + update.setString(3, uuid); + + return true; + } +} diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v74/PopulateTmpColumnsToCeQueue.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v74/PopulateTmpColumnsToCeQueue.java new file mode 100644 index 00000000000..e19e274bfd0 --- /dev/null +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v74/PopulateTmpColumnsToCeQueue.java @@ -0,0 +1,135 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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.v74; + +import java.sql.SQLException; +import org.sonar.db.Database; +import org.sonar.server.platform.db.migration.SupportsBlueGreen; +import org.sonar.server.platform.db.migration.step.DataChange; +import org.sonar.server.platform.db.migration.step.MassUpdate; +import org.sonar.server.platform.db.migration.step.Select; +import org.sonar.server.platform.db.migration.step.SqlStatement; + +@SupportsBlueGreen +public class PopulateTmpColumnsToCeQueue extends DataChange { + public PopulateTmpColumnsToCeQueue(Database db) { + super(db); + } + + @Override + protected void execute(Context context) throws SQLException { + // queued task of long and short branches which have already been analyzed at least once + populateCeQueueTmpColumns(context, "queued tasks of branches", + "select" + + " cq.uuid, p.uuid, cq.component_uuid" + + " from ce_queue cq" + + " inner join projects mp on mp.uuid = cq.component_uuid" + + " inner join ce_task_characteristics ctc1 on ctc1.task_uuid = cq.uuid and ctc1.kee = 'branchType'" + + " inner join ce_task_characteristics ctc2 on ctc2.task_uuid = cq.uuid and ctc2.kee = 'branch'" + + " inner join projects p on p.kee = concat(mp.kee, ':BRANCH:', ctc2.text_value)" + + " where" + + " cq.component_uuid is not null" + + " and (cq.tmp_component_uuid is null or cq.tmp_main_component_uuid is null)"); + + // queued task of pull request which have already been analyzed at least once + populateCeQueueTmpColumns(context, "queued tasks of PRs", + " select" + + " cq.uuid, p.uuid, cq.component_uuid" + + " from ce_queue cq" + + " inner join projects mp on mp.uuid = cq.component_uuid " + + " inner join ce_task_characteristics ctc1 on ctc1.task_uuid = cq.uuid and ctc1.kee = 'pullRequest'" + + " inner join projects p on p.kee = concat(mp.kee, ':PULL_REQUEST:', ctc1.text_value)" + + " where" + + " cq.component_uuid is not null" + + " and (cq.tmp_component_uuid is null or cq.tmp_main_component_uuid is null)"); + + // queued task of long and short branches which have never been analyzed must be deleted + deleteFromCeQueue(context, "queued tasks of never analyzed branches", + "select" + + " cq.uuid" + + " from ce_queue cq" + + " inner join projects mp on mp.uuid = cq.component_uuid" + + " inner join ce_task_characteristics ctc1 on ctc1.task_uuid = cq.uuid and ctc1.kee = 'branchType'" + + " inner join ce_task_characteristics ctc2 on ctc2.task_uuid = cq.uuid and ctc2.kee = 'branch'" + + " where" + + " cq.component_uuid is not null" + + " and (cq.tmp_component_uuid is null or cq.tmp_main_component_uuid is null)" + + " and not exists (select 1 from projects p where p.kee = concat(mp.kee, ':BRANCH:', ctc2.text_value))"); + + // queued of pull request which have never been analyzed must be deleted + deleteFromCeQueue(context, "queued tasks of never analyzed PRs", + "select" + + " cq.uuid" + + " from ce_queue cq" + + " inner join projects mp on mp.uuid = cq.component_uuid " + + " inner join ce_task_characteristics ctc1 on ctc1.task_uuid = cq.uuid and ctc1.kee = 'pullRequest'" + + " where" + + " cq.component_uuid is not null" + + " and (cq.tmp_component_uuid is null or cq.tmp_main_component_uuid is null)" + + " and not exists (select 1 from projects p where p.kee = concat(mp.kee, ':PULL_REQUEST:', ctc1.text_value))"); + + // all queue which tmp columns are not populated yet (will include main and deprecated branches) + // both tmp columns will be set to CE_QUEUE.COMPONENT_UUID + // do not join on PROJECTS to also catch orphans (there are many for branch and PRs due to SONAR-10642) + populateCeQueueTmpColumns(context, "queued tasks of main and deprecated branches", + "select" + + " cq.uuid, cq.component_uuid, cq.component_uuid" + + " from ce_queue cq" + + " where" + + " cq.component_uuid is not null" + + " and (cq.tmp_component_uuid is null or cq.tmp_main_component_uuid is null)"); + } + + private static void populateCeQueueTmpColumns(Context context, String pluralName, String selectSQL) throws SQLException { + MassUpdate massUpdate = context.prepareMassUpdate(); + massUpdate.select(selectSQL); + massUpdate.update("update ce_queue set tmp_component_uuid=?, tmp_main_component_uuid=? where uuid=?"); + massUpdate.rowPluralName(pluralName); + massUpdate.execute(PopulateTmpColumnsToCeQueue::handleUpdate); + } + + private static boolean handleUpdate(Select.Row row, SqlStatement update) throws SQLException { + String uuid = row.getString(1); + String componentUuuid = row.getString(2); + String mainComponentUuuid = row.getString(3); + + update.setString(1, componentUuuid); + update.setString(2, mainComponentUuuid); + update.setString(3, uuid); + + return true; + } + + private static void deleteFromCeQueue(Context context, String pluralName, String sql) throws SQLException { + MassUpdate massUpdate = context.prepareMassUpdate(); + massUpdate.select(sql); + massUpdate.update("delete from ce_queue where uuid = ?"); + massUpdate.rowPluralName(pluralName); + massUpdate.execute(PopulateTmpColumnsToCeQueue::handleDelete); + } + + private static boolean handleDelete(Select.Row row, SqlStatement update) throws SQLException { + String uuid = row.getString(1); + + update.setString(1, uuid); + + return true; + } +} diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v74/PopulateTmpLastKeyColumnsToCeActivity.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v74/PopulateTmpLastKeyColumnsToCeActivity.java new file mode 100644 index 00000000000..81b9340a751 --- /dev/null +++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v74/PopulateTmpLastKeyColumnsToCeActivity.java @@ -0,0 +1,83 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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.v74; + +import java.sql.SQLException; +import org.sonar.api.config.Configuration; +import org.sonar.db.Database; +import org.sonar.server.platform.db.migration.SupportsBlueGreen; +import org.sonar.server.platform.db.migration.step.DataChange; +import org.sonar.server.platform.db.migration.step.MassUpdate; +import org.sonar.server.platform.db.migration.step.Select; +import org.sonar.server.platform.db.migration.step.SqlStatement; + +@SupportsBlueGreen +public class PopulateTmpLastKeyColumnsToCeActivity extends DataChange { + private final Configuration configuration; + + public PopulateTmpLastKeyColumnsToCeActivity(Database db, Configuration configuration) { + super(db); + this.configuration = configuration; + } + + @Override + protected void execute(Context context) throws SQLException { + if (configuration.getBoolean("sonar.sonarcloud.enabled").orElse(false)) { + // data migration will be done in background so that interruption of service + // is reduced during upgrade + return; + } + + MassUpdate massUpdate = context.prepareMassUpdate(); + massUpdate.select("select" + + " cea.uuid, cea.task_type, cea.component_uuid, cea.tmp_component_uuid, cea.tmp_main_component_uuid" + + " from ce_activity cea" + + " where" + + " cea.tmp_is_last is null" + + " or cea.tmp_is_last_key is null" + + " or cea.tmp_main_is_last is null" + + " or cea.tmp_main_is_last_key is null"); + massUpdate.update("update ce_activity" + + " set" + + " tmp_is_last=?" + + " ,tmp_is_last_key=?" + + " ,tmp_main_is_last=?" + + " ,tmp_main_is_last_key=?" + + " where uuid=?"); + massUpdate.rowPluralName("rows of ce_activity"); + massUpdate.execute(PopulateTmpLastKeyColumnsToCeActivity::handleUpdate); + } + + private static boolean handleUpdate(Select.Row row, SqlStatement update) throws SQLException { + String uuid = row.getString(1); + String taskType = row.getString(2); + String oldComponentUuid = row.getString(3); + String componentUuuid = row.getString(4); + String mainComponentUuuid = row.getString(5); + + update.setBoolean(1, false); + update.setString(2, oldComponentUuid == null ? taskType : (taskType + componentUuuid)); + update.setBoolean(3, false); + update.setString(4, oldComponentUuid == null ? taskType : (taskType + mainComponentUuuid)); + update.setString(5, uuid); + + return true; + } +} diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v74/AddTmpColumnsToCeActivityTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v74/AddTmpColumnsToCeActivityTest.java new file mode 100644 index 00000000000..f0f703699d3 --- /dev/null +++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v74/AddTmpColumnsToCeActivityTest.java @@ -0,0 +1,56 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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.v74; + +import java.sql.SQLException; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.sonar.db.CoreDbTester; + +import static java.sql.Types.VARCHAR; + +public class AddTmpColumnsToCeActivityTest { + @Rule + public final CoreDbTester db = CoreDbTester.createForSchema(AddTmpColumnsToCeActivityTest.class, "ce_activity.sql"); + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + private AddTmpColumnsToCeActivity underTest = new AddTmpColumnsToCeActivity(db.database()); + + @Test + public void columns_and_indexes_are_added_to_table() throws SQLException { + underTest.execute(); + + db.assertColumnDefinition("ce_activity", "tmp_component_uuid", VARCHAR, 40, true); + db.assertColumnDefinition("ce_activity", "tmp_main_component_uuid", VARCHAR, 40, true); + db.assertIndex("ce_activity", "ce_activity_tmp_cpnt_uuid", "tmp_component_uuid"); + db.assertIndex("ce_activity", "ce_activity_tmp_main_cpnt_uuid", "tmp_main_component_uuid"); + } + + @Test + public void migration_is_not_reentrant() throws SQLException { + underTest.execute(); + + expectedException.expect(IllegalStateException.class); + + underTest.execute(); + } +} diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v74/AddTmpColumnsToCeQueueTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v74/AddTmpColumnsToCeQueueTest.java new file mode 100644 index 00000000000..97b062a8d9e --- /dev/null +++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v74/AddTmpColumnsToCeQueueTest.java @@ -0,0 +1,56 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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.v74; + +import java.sql.SQLException; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.sonar.db.CoreDbTester; + +import static java.sql.Types.VARCHAR; + +public class AddTmpColumnsToCeQueueTest { + @Rule + public final CoreDbTester db = CoreDbTester.createForSchema(AddTmpColumnsToCeQueueTest.class, "ce_queue.sql"); + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + private AddTmpColumnsToCeQueue underTest = new AddTmpColumnsToCeQueue(db.database()); + + @Test + public void columns_and_indexes_are_added_to_table() throws SQLException { + underTest.execute(); + + db.assertColumnDefinition("ce_queue", "tmp_component_uuid", VARCHAR, 40, true); + db.assertColumnDefinition("ce_queue", "tmp_main_component_uuid", VARCHAR, 40, true); + db.assertIndex("ce_queue", "ce_queue_tmp_cpnt_uuid", "tmp_component_uuid"); + db.assertIndex("ce_queue", "ce_queue_tmp_main_cpnt_uuid", "tmp_main_component_uuid"); + } + + @Test + public void migration_is_not_reentrant() throws SQLException { + underTest.execute(); + + expectedException.expect(IllegalStateException.class); + + underTest.execute(); + } +} diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v74/AddTmpLastKeyColumnsToCeActivityTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v74/AddTmpLastKeyColumnsToCeActivityTest.java new file mode 100644 index 00000000000..de71958cc25 --- /dev/null +++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v74/AddTmpLastKeyColumnsToCeActivityTest.java @@ -0,0 +1,62 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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.v74; + +import java.sql.SQLException; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.sonar.db.CoreDbTester; + +import static java.sql.Types.BOOLEAN; +import static java.sql.Types.VARCHAR; + +public class AddTmpLastKeyColumnsToCeActivityTest { + @Rule + public final CoreDbTester db = CoreDbTester.createForSchema(AddTmpLastKeyColumnsToCeActivityTest.class, "ce_activity.sql"); + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + private AddTmpLastKeyColumnsToCeActivity underTest = new AddTmpLastKeyColumnsToCeActivity(db.database()); + + @Test + public void columns_and_indexes_are_added_to_table() throws SQLException { + underTest.execute(); + + db.assertColumnDefinition("ce_activity", "tmp_is_last", BOOLEAN, null, true); + db.assertColumnDefinition("ce_activity", "tmp_is_last_key", VARCHAR, 55, true); + db.assertColumnDefinition("ce_activity", "tmp_main_is_last", BOOLEAN, null, true); + db.assertColumnDefinition("ce_activity", "tmp_main_is_last_key", VARCHAR, 55, true); + db.assertIndex("ce_activity", "ce_activity_t_islast_key", "tmp_is_last_key"); + db.assertIndex("ce_activity", "ce_activity_t_main_islast", "tmp_main_is_last", "status"); + db.assertIndex("ce_activity", "ce_activity_t_main_islast_key", "tmp_main_is_last_key"); + db.assertIndex("ce_activity", "ce_activity_t_main_islast", "tmp_main_is_last", "status"); + } + + @Test + public void migration_is_not_reentrant() throws SQLException { + underTest.execute(); + + expectedException.expect(IllegalStateException.class); + + underTest.execute(); + } + +} diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v74/DbVersion74Test.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v74/DbVersion74Test.java index 28dc704bf77..c0ba8282e1c 100644 --- a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v74/DbVersion74Test.java +++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v74/DbVersion74Test.java @@ -35,6 +35,6 @@ public class DbVersion74Test { @Test public void verify_migration_count() { - verifyMigrationCount(underTest, 5); + verifyMigrationCount(underTest, 11); } } diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v74/PopulateTmpColumnsToCeActivityTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v74/PopulateTmpColumnsToCeActivityTest.java new file mode 100644 index 00000000000..298ae547b9d --- /dev/null +++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v74/PopulateTmpColumnsToCeActivityTest.java @@ -0,0 +1,233 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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.v74; + +import com.google.common.collect.ImmutableMap; +import com.tngtech.java.junit.dataprovider.DataProvider; +import com.tngtech.java.junit.dataprovider.DataProviderRunner; +import com.tngtech.java.junit.dataprovider.UseDataProvider; +import java.sql.SQLException; +import java.util.Collections; +import java.util.Map; +import java.util.Random; +import java.util.stream.Stream; +import javax.annotation.Nullable; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.sonar.api.config.internal.MapSettings; +import org.sonar.db.CoreDbTester; + +import static java.util.Arrays.stream; +import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic; +import static org.assertj.core.api.Assertions.assertThat; + +@RunWith(DataProviderRunner.class) +public class PopulateTmpColumnsToCeActivityTest { + private static final Map<String, String> NO_CHARACTERISTICS = Collections.emptyMap(); + + @Rule + public CoreDbTester db = CoreDbTester.createForSchema(PopulateTmpColumnsToCeActivityTest.class, "ce_activity.sql"); + + private MapSettings settings = new MapSettings(); + private PopulateTmpColumnsToCeActivity underTest = new PopulateTmpColumnsToCeActivity(db.database(), settings.asConfig()); + + @Test + public void execute_has_no_effect_on_empty_table() throws SQLException { + underTest.execute(); + + assertThat(rowsInCeActivity()).isEmpty(); + } + + @Test + public void execute_has_no_effect_on_empty_table_on_sonarcloud() throws SQLException { + settings.setProperty("sonar.sonarcloud.enabled", true); + + underTest.execute(); + + assertThat(rowsInCeActivity()).isEmpty(); + } + + @Test + @UseDataProvider("characteriticsOfMainBranchesAndPr") + public void execute_populates_tmp_columns_with_component_uuid_if_task_has_no_row_in_PROJECTS(Map<String, String> characteristics) throws SQLException { + Row[] notUpdatedRows = Stream.of( + // not updated because no component_uuid + new Row(newUuid(), null, null, null), + new Row(newUuid(), null, randomAlphabetic(2), null), + new Row(newUuid(), null, randomAlphabetic(3), randomAlphabetic(4)), + new Row(newUuid(), null, null, randomAlphabetic(5)), + // not updated because both target fields are already set (re-entrance) + new Row(newUuid(), randomAlphabetic(14), randomAlphabetic(6), randomAlphabetic(7))) + .toArray(Row[]::new); + Row[] updatedRows = { + new Row(newUuid(), randomAlphabetic(12), null, null), + new Row(newUuid(), randomAlphabetic(13), randomAlphabetic(5), null), + new Row(newUuid(), randomAlphabetic(14), null, randomAlphabetic(6)), + }; + stream(notUpdatedRows).forEach(row -> insertCeActivity(row, characteristics)); + stream(updatedRows).forEach(row -> insertCeActivity(row, characteristics)); + + underTest.execute(); + + assertThat(rowsInCeActivity()) + .hasSize(notUpdatedRows.length + updatedRows.length) + .contains(notUpdatedRows) + .contains(stream(updatedRows) + .map(row -> new Row(row.taskUuid, row.componentUuid, row.componentUuid, row.componentUuid)) + .toArray(Row[]::new)); + } + + @DataProvider + public static Object[][] characteriticsOfMainBranchesAndPr() { + return new Object[][] { + {NO_CHARACTERISTICS}, + {branchCharacteristics("LONG", randomAlphabetic(15))}, + {branchCharacteristics("SHORT", randomAlphabetic(16))}, + {branchCharacteristics(randomAlphabetic(17), randomAlphabetic(18))}, + {prCharacteristics(randomAlphabetic(19))}, + }; + } + + @Test + public void execute_populates_tmp_columns_with_component_uuid_for_existing_main_branch() throws SQLException { + String mainComponentUuid = randomAlphabetic(2); + insertProjects(mainComponentUuid, randomAlphabetic(3)); + String taskUuid = insertCeActivity(new Row(newUuid(), mainComponentUuid, null, null), NO_CHARACTERISTICS); + + underTest.execute(); + + assertThat(rowsInCeActivity()) + .containsOnly(new Row(taskUuid, mainComponentUuid, mainComponentUuid, mainComponentUuid)); + } + + @Test + public void execute_deletes_populates_branches_of_task_without_row_in_PROJECTS_with_COMPONENT_UUID_and_those_with_row_in_PROJECTS_by_KEE() throws SQLException { + String mainComponentUuid = randomAlphabetic(2); + String mainComponentKey = randomAlphabetic(3); + String branchUuid = randomAlphabetic(4); + String branchType1 = randomAlphabetic(5); + String branchName1 = randomAlphabetic(6); + String branchType2 = randomAlphabetic(7); + String branchName2 = randomAlphabetic(8); + insertProjects(mainComponentUuid, mainComponentKey); + insertProjects(branchUuid, mainComponentKey + ":BRANCH:" + branchName2); + String orphanTaskUuid = insertCeActivity(new Row(newUuid(), mainComponentUuid, null, null), branchCharacteristics(branchType1, branchName1)); + String regularTaskUuid = insertCeActivity(new Row(newUuid(), mainComponentUuid, null, null), branchCharacteristics(branchType2, branchName2)); + + underTest.execute(); + + assertThat(rowsInCeActivity()) + .containsOnly( + new Row(orphanTaskUuid, mainComponentUuid, mainComponentUuid, mainComponentUuid), + new Row(regularTaskUuid, mainComponentUuid, branchUuid, mainComponentUuid)); + } + + @Test + public void execute_deletes_populates_prs_of_task_without_row_in_PROJECTS_with_COMPONENT_UUID_and_those_with_row_in_PROJECTS_by_KEE() throws SQLException { + String mainComponentUuid = randomAlphabetic(2); + String mainComponentKey = randomAlphabetic(3); + String prUuid = randomAlphabetic(4); + String prName1 = randomAlphabetic(6); + String prName2 = randomAlphabetic(8); + insertProjects(mainComponentUuid, mainComponentKey); + insertProjects(prUuid, mainComponentKey + ":PULL_REQUEST:" + prName2); + String orphanTaskUuid = insertCeActivity(new Row(newUuid(), mainComponentUuid, null, null), prCharacteristics(prName1)); + String regularTaskUuid = insertCeActivity(new Row(newUuid(), mainComponentUuid, null, null), prCharacteristics(prName2)); + + underTest.execute(); + + assertThat(rowsInCeActivity()) + .containsOnly( + new Row(orphanTaskUuid, mainComponentUuid, mainComponentUuid, mainComponentUuid), + new Row(regularTaskUuid, mainComponentUuid, prUuid, mainComponentUuid)); + } + + private Stream<Row> rowsInCeActivity() { + return db.select("select" + + " uuid as \"UUID\", component_uuid as \"COMPONENT_UUID\", tmp_component_uuid as \"TMP_COMPONENT_UUID\", tmp_main_component_UUID as \"TMP_MAIN_COMPONENT_UUID\"" + + " from ce_activity") + .stream() + .map(row -> new Row( + (String) row.get("UUID"), + (String) row.get("COMPONENT_UUID"), + (String) row.get("TMP_COMPONENT_UUID"), + (String) row.get("TMP_MAIN_COMPONENT_UUID"))); + } + + private String insertCeActivity(Row row, Map<String, String> characteristics) { + String uuid = insertCeActivity(row.taskUuid, row.componentUuid, row.tmpComponentUuid, row.tmpMainComponentUuid); + characteristics.forEach((key, value) -> insertCeCharacteristic(uuid, key, value)); + return uuid; + } + + private String insertCeActivity(String uuid, @Nullable String componentUuid, @Nullable String tmpComponentUuid, @Nullable String tmpMainComponentUuid) { + Random random = new Random(); + db.executeInsert("ce_activity", + "UUID", uuid, + "TASK_TYPE", randomAlphabetic(6), + "COMPONENT_UUID", componentUuid, + "TMP_COMPONENT_UUID", tmpComponentUuid, + "TMP_MAIN_COMPONENT_UUID", tmpMainComponentUuid, + "STATUS", randomAlphabetic(7), + "IS_LAST", random.nextBoolean(), + "IS_LAST_KEY", random.nextBoolean(), + "EXECUTION_COUNT", random.nextInt(500), + "SUBMITTED_AT", (long) random.nextInt(500), + "CREATED_AT", (long) random.nextInt(500), + "UPDATED_AT", (long) random.nextInt(500)); + return uuid; + } + + private void insertCeCharacteristic(String taskUuid, String key, String value) { + db.executeInsert( + "ce_task_characteristics", + "UUID", newUuid(), + "TASK_UUID", taskUuid, + "KEE", key, + "TEXT_VALUE", value); + } + + private void insertProjects(String uuid, String key) { + db.executeInsert( + "PROJECTS", + "UUID", uuid, + "KEE", key, + "ORGANIZATION_UUID", "org_" + uuid, + "ROOT_UUID", uuid + "_root", + "UUID_PATH", uuid + "_path", + "PROJECT_UUID", uuid + "_project", + "PRIVATE", new Random().nextBoolean()); + } + + private int uuidGenerator = new Random().nextInt(9000); + + private String newUuid() { + return "uuid_" + uuidGenerator++; + } + + private static Map<String, String> branchCharacteristics(String branchType, String branchName) { + return ImmutableMap.of("branchType", branchType, "branch", branchName); + } + + private static Map<String, String> prCharacteristics(String prName) { + return ImmutableMap.of("pullRequest", prName); + } +} diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v74/PopulateTmpColumnsToCeQueueTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v74/PopulateTmpColumnsToCeQueueTest.java new file mode 100644 index 00000000000..866eaa49026 --- /dev/null +++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v74/PopulateTmpColumnsToCeQueueTest.java @@ -0,0 +1,216 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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.v74; + +import com.google.common.collect.ImmutableMap; +import com.tngtech.java.junit.dataprovider.DataProvider; +import com.tngtech.java.junit.dataprovider.DataProviderRunner; +import com.tngtech.java.junit.dataprovider.UseDataProvider; +import java.sql.SQLException; +import java.util.Collections; +import java.util.Map; +import java.util.Random; +import java.util.stream.Stream; +import javax.annotation.Nullable; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.sonar.db.CoreDbTester; + +import static java.util.Arrays.stream; +import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic; +import static org.assertj.core.api.Assertions.assertThat; + +@RunWith(DataProviderRunner.class) +public class PopulateTmpColumnsToCeQueueTest { + private static final Map<String, String> NO_CHARACTERISTICS = Collections.emptyMap(); + + @Rule + public CoreDbTester db = CoreDbTester.createForSchema(PopulateTmpColumnsToCeQueueTest.class, "ce_queue.sql"); + + private PopulateTmpColumnsToCeQueue underTest = new PopulateTmpColumnsToCeQueue(db.database()); + + @Test + public void no_action_on_empty_table() throws SQLException { + underTest.execute(); + + assertThat(db.countRowsOfTable("ce_queue")).isZero(); + } + + @Test + @UseDataProvider("characteriticsOfMainBranchesAndPr") + public void execute_populates_tmp_columns_with_component_uuid_if_task_has_no_row_in_PROJECTS(Map<String, String> characteristics) throws SQLException { + Row[] notUpdatedRows = Stream.of( + // not updated because no component_uuid + new Row(newUuid(), null, null, null), + new Row(newUuid(), null, randomAlphabetic(2), null), + new Row(newUuid(), null, randomAlphabetic(3), randomAlphabetic(4)), + new Row(newUuid(), null, null, randomAlphabetic(5)), + // not updated because both target fields are already set (re-entrance) + new Row(newUuid(), randomAlphabetic(14), randomAlphabetic(6), randomAlphabetic(7))) + .toArray(Row[]::new); + Row[] updatedRows = { + new Row(newUuid(), randomAlphabetic(12), null, null), + new Row(newUuid(), randomAlphabetic(13), randomAlphabetic(5), null), + new Row(newUuid(), randomAlphabetic(14), null, randomAlphabetic(6)), + }; + stream(notUpdatedRows).forEach(row -> insertCeQueue(row, characteristics)); + stream(updatedRows).forEach(row -> insertCeQueue(row, characteristics)); + + underTest.execute(); + + assertThat(rowsInCeQueue()) + .hasSize(notUpdatedRows.length + updatedRows.length) + .contains(notUpdatedRows) + .contains(stream(updatedRows) + .map(row -> new Row(row.taskUuid, row.componentUuid, row.componentUuid, row.componentUuid)) + .toArray(Row[]::new)); + } + + @DataProvider + public static Object[][] characteriticsOfMainBranchesAndPr() { + return new Object[][] { + {NO_CHARACTERISTICS}, + {branchCharacteristics("LONG", randomAlphabetic(15))}, + {branchCharacteristics("SHORT", randomAlphabetic(16))}, + {branchCharacteristics(randomAlphabetic(17), randomAlphabetic(18))}, + {prCharacteristics(randomAlphabetic(19))}, + }; + } + + @Test + public void execute_populates_tmp_columns_with_component_uuid_for_existing_main_branch() throws SQLException { + String mainComponentUuid = randomAlphabetic(2); + insertProjects(mainComponentUuid, randomAlphabetic(3)); + String taskUuid = insertCeQueue(new Row(newUuid(), mainComponentUuid, null, null), NO_CHARACTERISTICS); + + underTest.execute(); + + assertThat(rowsInCeQueue()) + .containsOnly(new Row(taskUuid, mainComponentUuid, mainComponentUuid, mainComponentUuid)); + } + + @Test + public void execute_deletes_tasks_of_branches_without_row_in_PROJECTS_and_populates_others_matching_row_in_PROJECTS_by_KEE() throws SQLException { + String mainComponentUuid = randomAlphabetic(2); + String mainComponentKey = randomAlphabetic(3); + String branchUuid = randomAlphabetic(4); + String branchType1 = randomAlphabetic(5); + String branchName1 = randomAlphabetic(6); + String branchType2 = randomAlphabetic(7); + String branchName2 = randomAlphabetic(8); + insertProjects(mainComponentUuid, mainComponentKey); + insertProjects(branchUuid, mainComponentKey + ":BRANCH:" + branchName2); + String deletedTaskUuid = insertCeQueue(new Row(newUuid(), mainComponentUuid, null, null), branchCharacteristics(branchType1, branchName1)); + String updatedTaskUuid = insertCeQueue(new Row(newUuid(), mainComponentUuid, null, null), branchCharacteristics(branchType2, branchName2)); + + underTest.execute(); + + assertThat(rowsInCeQueue()) + .containsOnly(new Row(updatedTaskUuid, mainComponentUuid, branchUuid, mainComponentUuid)); + } + + @Test + public void execute_deletes_tasks_of_prs_without_row_in_PROJECTS_and_populates_others_matching_row_in_PROJECTS_by_KEE() throws SQLException { + String mainComponentUuid = randomAlphabetic(2); + String mainComponentKey = randomAlphabetic(3); + String prUuid = randomAlphabetic(4); + String prName1 = randomAlphabetic(6); + String prName2 = randomAlphabetic(8); + insertProjects(mainComponentUuid, mainComponentKey); + insertProjects(prUuid, mainComponentKey + ":PULL_REQUEST:" + prName2); + String deletedTaskUuid = insertCeQueue(new Row(newUuid(), mainComponentUuid, null, null), prCharacteristics(prName1)); + String updatedTaskUuid = insertCeQueue(new Row(newUuid(), mainComponentUuid, null, null), prCharacteristics(prName2)); + + underTest.execute(); + + assertThat(rowsInCeQueue()) + .containsOnly(new Row(updatedTaskUuid, mainComponentUuid, prUuid, mainComponentUuid)); + } + + private Stream<Row> rowsInCeQueue() { + return db.select("select" + + " uuid as \"UUID\", component_uuid as \"COMPONENT_UUID\", tmp_component_uuid as \"TMP_COMPONENT_UUID\", tmp_main_component_UUID as \"TMP_MAIN_COMPONENT_UUID\"" + + " from ce_queue") + .stream() + .map(row -> new Row( + (String) row.get("UUID"), + (String) row.get("COMPONENT_UUID"), + (String) row.get("TMP_COMPONENT_UUID"), + (String) row.get("TMP_MAIN_COMPONENT_UUID"))); + } + + private String insertCeQueue(Row row, Map<String, String> characteristics) { + String uuid = insertCeQueue(row.taskUuid, row.componentUuid, row.tmpComponentUuid, row.tmpMainComponentUuid); + characteristics.forEach((key, value) -> insertCeCharacteristic(uuid, key, value)); + return uuid; + } + + private String insertCeQueue(String uuid, @Nullable String componentUuid, @Nullable String tmpComponentUuid, @Nullable String tmpMainComponentUuid) { + Random random = new Random(); + db.executeInsert("ce_queue", + "UUID", uuid, + "TASK_TYPE", randomAlphabetic(6), + "COMPONENT_UUID", componentUuid, + "TMP_COMPONENT_UUID", tmpComponentUuid, + "TMP_MAIN_COMPONENT_UUID", tmpMainComponentUuid, + "STATUS", randomAlphabetic(7), + "EXECUTION_COUNT", random.nextInt(500), + "CREATED_AT", (long) random.nextInt(500), + "UPDATED_AT", (long) random.nextInt(500)); + return uuid; + } + + private void insertCeCharacteristic(String taskUuid, String key, String value) { + db.executeInsert( + "ce_task_characteristics", + "UUID", newUuid(), + "TASK_UUID", taskUuid, + "KEE", key, + "TEXT_VALUE", value); + } + + private void insertProjects(String uuid, String key) { + db.executeInsert( + "PROJECTS", + "UUID", uuid, + "KEE", key, + "ORGANIZATION_UUID", "org_" + uuid, + "ROOT_UUID", uuid + "_root", + "UUID_PATH", uuid + "_path", + "PROJECT_UUID", uuid + "_project", + "PRIVATE", new Random().nextBoolean()); + } + + private int uuidGenerator = new Random().nextInt(9000); + + private String newUuid() { + return "uuid_" + uuidGenerator++; + } + + private static Map<String, String> branchCharacteristics(String branchType, String branchName) { + return ImmutableMap.of("branchType", branchType, "branch", branchName); + } + + private static Map<String, String> prCharacteristics(String prName) { + return ImmutableMap.of("pullRequest", prName); + } + +} diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v74/PopulateTmpLastKeyColumnsToCeActivityTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v74/PopulateTmpLastKeyColumnsToCeActivityTest.java new file mode 100644 index 00000000000..ae4bd591e82 --- /dev/null +++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v74/PopulateTmpLastKeyColumnsToCeActivityTest.java @@ -0,0 +1,118 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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.v74; + +import java.sql.SQLException; +import java.util.List; +import java.util.Random; +import javax.annotation.Nullable; +import org.assertj.core.api.AbstractIterableAssert; +import org.assertj.core.api.ObjectAssert; +import org.assertj.core.groups.Tuple; +import org.junit.Rule; +import org.junit.Test; +import org.sonar.api.config.internal.MapSettings; +import org.sonar.core.util.UuidFactoryFast; +import org.sonar.db.CoreDbTester; + +import static com.google.common.base.Preconditions.checkArgument; +import static org.apache.commons.lang.RandomStringUtils.randomAlphabetic; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.tuple; + +public class PopulateTmpLastKeyColumnsToCeActivityTest { + + @Rule + public CoreDbTester db = CoreDbTester.createForSchema(PopulateTmpLastKeyColumnsToCeActivityTest.class, "ce_activity.sql"); + + private MapSettings settings = new MapSettings(); + private PopulateTmpLastKeyColumnsToCeActivity underTest = new PopulateTmpLastKeyColumnsToCeActivity(db.database(), settings.asConfig()); + + @Test + public void execute_has_no_effect_on_empty_table() throws SQLException { + underTest.execute(); + + assertThat(db.countRowsOfTable("ce_activity")).isZero(); + } + + @Test + public void execute_populate_tmp_last_key_columns_from_type_and_component_uuid_columns() throws SQLException { + String type = randomAlphabetic(6); + String oldComponentUuid = randomAlphabetic(7); + String tmpComponentUuid = randomAlphabetic(8); + String tmpMainComponentUuid = randomAlphabetic(9); + + String taskWithComponentUuid = insertCeActivity(type, oldComponentUuid, tmpComponentUuid, tmpMainComponentUuid); + String taskWithInconsistentComponentUuid = insertCeActivity(type, null, tmpComponentUuid, tmpMainComponentUuid); + String taskNoComponentUuid = insertCeActivity(type, null, null, null); + + underTest.execute(); + + assertThatTmpLastKeyAndMainLastKeyOf(taskWithComponentUuid).containsOnly(tuple(type + tmpComponentUuid, type + tmpMainComponentUuid)); + assertThatTmpLastKeyAndMainLastKeyOf(taskWithInconsistentComponentUuid).containsOnly(tuple(type, type)); + assertThatTmpLastKeyAndMainLastKeyOf(taskNoComponentUuid).containsOnly(tuple(type, type)); + + assertThatTmpIsLastAndMainIsLastOf(taskWithComponentUuid).containsOnly(tuple(false, false)); + assertThatTmpIsLastAndMainIsLastOf(taskWithInconsistentComponentUuid).containsOnly(tuple(false, false)); + assertThatTmpIsLastAndMainIsLastOf(taskNoComponentUuid).containsOnly(tuple(false, false)); + } + @Test + public void execute_is_reentrant() throws SQLException { + execute_populate_tmp_last_key_columns_from_type_and_component_uuid_columns(); + + underTest.execute(); + } + + private String insertCeActivity(String type, + @Nullable String oldComponentUuid, + @Nullable String tmpComponentUuid, @Nullable String tmpMainComponentUuid) { + checkArgument((tmpComponentUuid == null) == (tmpMainComponentUuid == null)); + + String uuid = UuidFactoryFast.getInstance().create(); + + Random random = new Random(); + db.executeInsert( + "ce_activity", + "UUID", uuid, + "TASK_TYPE", type, + "COMPONENT_UUID", oldComponentUuid, + "TMP_COMPONENT_UUID", tmpComponentUuid, + "TMP_MAIN_COMPONENT_UUID", tmpMainComponentUuid, + "STATUS", randomAlphabetic(5), + "IS_LAST", random.nextBoolean(), + "IS_LAST_KEY", randomAlphabetic(12), + "EXECUTION_COUNT", random.nextInt(10), + "SUBMITTED_AT", (long) random.nextInt(5_999), + "CREATED_AT", (long) random.nextInt(5_999), + "UPDATED_AT", (long) random.nextInt(5_999)); + + return uuid; + } + + private AbstractIterableAssert<?, List<? extends Tuple>, Tuple, ObjectAssert<Tuple>> assertThatTmpLastKeyAndMainLastKeyOf(String uuid) { + return assertThat(db.select("select tmp_is_last_key as \"LAST_KEY\", tmp_main_is_last_key as \"MAIN_LAST_KEY\" from ce_activity where uuid='" + uuid + "'")) + .extracting(t -> (String) t.get("LAST_KEY"), t -> (String) t.get("MAIN_LAST_KEY")); + } + + private AbstractIterableAssert<?, List<? extends Tuple>, Tuple, ObjectAssert<Tuple>> assertThatTmpIsLastAndMainIsLastOf(String uuid) { + return assertThat(db.select("select tmp_is_last as \"LAST\", tmp_main_is_last as \"MAIN_LAST\" from ce_activity where uuid='" + uuid + "'")) + .extracting(t -> (Boolean) t.get("LAST"), t -> (Boolean) t.get("MAIN_LAST")); + } +} diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v74/Row.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v74/Row.java new file mode 100644 index 00000000000..5ba77192079 --- /dev/null +++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v74/Row.java @@ -0,0 +1,67 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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.v74; + +import java.util.Objects; +import javax.annotation.Nullable; + +final class Row { + final String taskUuid; + final String componentUuid; + final String tmpComponentUuid; + final String tmpMainComponentUuid; + + Row(String taskUuid, @Nullable String componentUuid, @Nullable String tmpComponentUuid, @Nullable String tmpMainComponentUuid) { + this.taskUuid = taskUuid; + this.componentUuid = componentUuid; + this.tmpComponentUuid = tmpComponentUuid; + this.tmpMainComponentUuid = tmpMainComponentUuid; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Row row = (Row) o; + return Objects.equals(taskUuid, row.taskUuid) && + Objects.equals(componentUuid, row.componentUuid) && + Objects.equals(tmpComponentUuid, row.tmpComponentUuid) && + Objects.equals(tmpMainComponentUuid, row.tmpMainComponentUuid); + } + + @Override + public int hashCode() { + return Objects.hash(taskUuid, componentUuid, tmpComponentUuid, tmpMainComponentUuid); + } + + @Override + public String toString() { + return "Row{" + + "uuid='" + taskUuid + '\'' + + ", componentUuid='" + componentUuid + '\'' + + ", tmpComponentUuid='" + tmpComponentUuid + '\'' + + ", tmpMainComponentUuid='" + tmpMainComponentUuid + '\'' + + '}'; + } +} diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v74/AddTmpColumnsToCeActivityTest/ce_activity.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v74/AddTmpColumnsToCeActivityTest/ce_activity.sql new file mode 100644 index 00000000000..540c11a8dd5 --- /dev/null +++ b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v74/AddTmpColumnsToCeActivityTest/ce_activity.sql @@ -0,0 +1,26 @@ +CREATE TABLE "CE_ACTIVITY" ( + "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), + "UUID" VARCHAR(40) NOT NULL, + "TASK_TYPE" VARCHAR(15) NOT NULL, + "COMPONENT_UUID" VARCHAR(40) NULL, + "ANALYSIS_UUID" VARCHAR(50) NULL, + "STATUS" VARCHAR(15) NOT NULL, + "IS_LAST" BOOLEAN NOT NULL, + "IS_LAST_KEY" VARCHAR(55) NOT NULL, + "SUBMITTER_UUID" VARCHAR(255) NULL, + "WORKER_UUID" VARCHAR(40) NULL, + "EXECUTION_COUNT" INTEGER NOT NULL, + "SUBMITTED_AT" BIGINT NOT NULL, + "STARTED_AT" BIGINT NULL, + "EXECUTED_AT" BIGINT NULL, + "CREATED_AT" BIGINT NOT NULL, + "UPDATED_AT" BIGINT NOT NULL, + "EXECUTION_TIME_MS" BIGINT NULL, + "ERROR_MESSAGE" VARCHAR(1000), + "ERROR_STACKTRACE" CLOB, + "ERROR_TYPE" VARCHAR(20) +); +CREATE UNIQUE INDEX "CE_ACTIVITY_UUID" ON "CE_ACTIVITY" ("UUID"); +CREATE INDEX "CE_ACTIVITY_COMPONENT_UUID" ON "CE_ACTIVITY" ("COMPONENT_UUID"); +CREATE INDEX "CE_ACTIVITY_ISLASTKEY" ON "CE_ACTIVITY" ("IS_LAST_KEY"); +CREATE INDEX "CE_ACTIVITY_ISLAST_STATUS" ON "CE_ACTIVITY" ("IS_LAST", "STATUS"); diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v74/AddTmpColumnsToCeQueueTest/ce_queue.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v74/AddTmpColumnsToCeQueueTest/ce_queue.sql new file mode 100644 index 00000000000..b1282536589 --- /dev/null +++ b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v74/AddTmpColumnsToCeQueueTest/ce_queue.sql @@ -0,0 +1,16 @@ +CREATE TABLE "CE_QUEUE" ( + "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), + "UUID" VARCHAR(40) NOT NULL, + "TASK_TYPE" VARCHAR(15) NOT NULL, + "COMPONENT_UUID" VARCHAR(40) NULL, + "STATUS" VARCHAR(15) NOT NULL, + "SUBMITTER_UUID" VARCHAR(255) NULL, + "WORKER_UUID" VARCHAR(40) NULL, + "EXECUTION_COUNT" INTEGER NOT NULL, + "STARTED_AT" BIGINT NULL, + "CREATED_AT" BIGINT NOT NULL, + "UPDATED_AT" BIGINT NOT NULL +); +CREATE UNIQUE INDEX "CE_QUEUE_UUID" ON "CE_QUEUE" ("UUID"); +CREATE INDEX "CE_QUEUE_COMPONENT_UUID" ON "CE_QUEUE" ("COMPONENT_UUID"); +CREATE INDEX "CE_QUEUE_STATUS" ON "CE_QUEUE" ("STATUS"); diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v74/AddTmpLastKeyColumnsToCeActivityTest/ce_activity.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v74/AddTmpLastKeyColumnsToCeActivityTest/ce_activity.sql new file mode 100644 index 00000000000..fb0d7303aae --- /dev/null +++ b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v74/AddTmpLastKeyColumnsToCeActivityTest/ce_activity.sql @@ -0,0 +1,30 @@ +CREATE TABLE "CE_ACTIVITY" ( + "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), + "UUID" VARCHAR(40) NOT NULL, + "TASK_TYPE" VARCHAR(15) NOT NULL, + "COMPONENT_UUID" VARCHAR(40) NULL, + "TMP_COMPONENT_UUID" VARCHAR(40) NULL, + "TMP_MAIN_COMPONENT_UUID" VARCHAR(40) NULL, + "ANALYSIS_UUID" VARCHAR(50) NULL, + "STATUS" VARCHAR(15) NOT NULL, + "IS_LAST" BOOLEAN NOT NULL, + "IS_LAST_KEY" VARCHAR(55) NOT NULL, + "SUBMITTER_UUID" VARCHAR(255) NULL, + "WORKER_UUID" VARCHAR(40) NULL, + "EXECUTION_COUNT" INTEGER NOT NULL, + "SUBMITTED_AT" BIGINT NOT NULL, + "STARTED_AT" BIGINT NULL, + "EXECUTED_AT" BIGINT NULL, + "CREATED_AT" BIGINT NOT NULL, + "UPDATED_AT" BIGINT NOT NULL, + "EXECUTION_TIME_MS" BIGINT NULL, + "ERROR_MESSAGE" VARCHAR(1000), + "ERROR_STACKTRACE" CLOB, + "ERROR_TYPE" VARCHAR(20) +); +CREATE UNIQUE INDEX "CE_ACTIVITY_UUID" ON "CE_ACTIVITY" ("UUID"); +CREATE INDEX "CE_ACTIVITY_COMPONENT_UUID" ON "CE_ACTIVITY" ("COMPONENT_UUID"); +CREATE INDEX "CE_ACTIVITY_TMP_CMPT_UUID" ON "CE_ACTIVITY" ("TMP_COMPONENT_UUID"); +CREATE INDEX "CE_ACTIVITY_TMP_MAIN_CMPT_UUID" ON "CE_ACTIVITY" ("TMP_MAIN_COMPONENT_UUID"); +CREATE INDEX "CE_ACTIVITY_ISLASTKEY" ON "CE_ACTIVITY" ("IS_LAST_KEY"); +CREATE INDEX "CE_ACTIVITY_ISLAST_STATUS" ON "CE_ACTIVITY" ("IS_LAST", "STATUS"); diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v74/PopulateTmpColumnsToCeActivityTest/ce_activity.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v74/PopulateTmpColumnsToCeActivityTest/ce_activity.sql new file mode 100644 index 00000000000..68242f666e7 --- /dev/null +++ b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v74/PopulateTmpColumnsToCeActivityTest/ce_activity.sql @@ -0,0 +1,87 @@ +CREATE TABLE "CE_ACTIVITY" ( + "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), + "UUID" VARCHAR(40) NOT NULL, + "TASK_TYPE" VARCHAR(15) NOT NULL, + "COMPONENT_UUID" VARCHAR(40) NULL, + "TMP_COMPONENT_UUID" VARCHAR(40) NULL, + "TMP_MAIN_COMPONENT_UUID" VARCHAR(40) NULL, + "ANALYSIS_UUID" VARCHAR(50) NULL, + "STATUS" VARCHAR(15) NOT NULL, + "IS_LAST" BOOLEAN NOT NULL, + "IS_LAST_KEY" VARCHAR(55) NOT NULL, + "SUBMITTER_UUID" VARCHAR(255) NULL, + "WORKER_UUID" VARCHAR(40) NULL, + "EXECUTION_COUNT" INTEGER NOT NULL, + "SUBMITTED_AT" BIGINT NOT NULL, + "STARTED_AT" BIGINT NULL, + "EXECUTED_AT" BIGINT NULL, + "CREATED_AT" BIGINT NOT NULL, + "UPDATED_AT" BIGINT NOT NULL, + "EXECUTION_TIME_MS" BIGINT NULL, + "ERROR_MESSAGE" VARCHAR(1000), + "ERROR_STACKTRACE" CLOB, + "ERROR_TYPE" VARCHAR(20) +); +CREATE UNIQUE INDEX "CE_ACTIVITY_UUID" ON "CE_ACTIVITY" ("UUID"); +CREATE INDEX "CE_ACTIVITY_COMPONENT_UUID" ON "CE_ACTIVITY" ("COMPONENT_UUID"); +CREATE INDEX "CE_ACTIVITY_TMP_CMPT_UUID" ON "CE_ACTIVITY" ("TMP_COMPONENT_UUID"); +CREATE INDEX "CE_ACTIVITY_TMP_MAIN_CMPT_UUID" ON "CE_ACTIVITY" ("TMP_MAIN_COMPONENT_UUID"); +CREATE INDEX "CE_ACTIVITY_ISLASTKEY" ON "CE_ACTIVITY" ("IS_LAST_KEY"); +CREATE INDEX "CE_ACTIVITY_ISLAST_STATUS" ON "CE_ACTIVITY" ("IS_LAST", "STATUS"); + +CREATE TABLE "CE_TASK_CHARACTERISTICS" ( + "UUID" VARCHAR(40) NOT NULL, + "TASK_UUID" VARCHAR(40) NOT NULL, + "KEE" VARCHAR(50) NOT NULL, + "TEXT_VALUE" VARCHAR(4000), + + CONSTRAINT "PK_CE_TASK_CHARACTERISTICS" PRIMARY KEY ("UUID") +); +CREATE INDEX "CE_TASK_CHARACTERISTICS_TASK_UUID" ON "CE_TASK_CHARACTERISTICS" ("TASK_UUID"); + +CREATE TABLE "PROJECTS" ( + "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), + "ORGANIZATION_UUID" VARCHAR(40) NOT NULL, + "KEE" VARCHAR(400), + "UUID" VARCHAR(50) NOT NULL, + "UUID_PATH" VARCHAR(1500) NOT NULL, + "ROOT_UUID" VARCHAR(50) NOT NULL, + "PROJECT_UUID" VARCHAR(50) NOT NULL, + "MODULE_UUID" VARCHAR(50), + "MODULE_UUID_PATH" VARCHAR(1500), + "MAIN_BRANCH_PROJECT_UUID" VARCHAR(50), + "NAME" VARCHAR(2000), + "DESCRIPTION" VARCHAR(2000), + "PRIVATE" BOOLEAN NOT NULL, + "TAGS" VARCHAR(500), + "ENABLED" BOOLEAN NOT NULL DEFAULT TRUE, + "SCOPE" VARCHAR(3), + "QUALIFIER" VARCHAR(10), + "DEPRECATED_KEE" VARCHAR(400), + "PATH" VARCHAR(2000), + "LANGUAGE" VARCHAR(20), + "COPY_COMPONENT_UUID" VARCHAR(50), + "LONG_NAME" VARCHAR(2000), + "DEVELOPER_UUID" VARCHAR(50), + "CREATED_AT" TIMESTAMP, + "AUTHORIZATION_UPDATED_AT" BIGINT, + "B_CHANGED" BOOLEAN, + "B_COPY_COMPONENT_UUID" VARCHAR(50), + "B_DESCRIPTION" VARCHAR(2000), + "B_ENABLED" BOOLEAN, + "B_UUID_PATH" VARCHAR(1500), + "B_LANGUAGE" VARCHAR(20), + "B_LONG_NAME" VARCHAR(500), + "B_MODULE_UUID" VARCHAR(50), + "B_MODULE_UUID_PATH" VARCHAR(1500), + "B_NAME" VARCHAR(500), + "B_PATH" VARCHAR(2000), + "B_QUALIFIER" VARCHAR(10) +); +CREATE INDEX "PROJECTS_ORGANIZATION" ON "PROJECTS" ("ORGANIZATION_UUID"); +CREATE UNIQUE INDEX "PROJECTS_KEE" ON "PROJECTS" ("KEE"); +CREATE INDEX "PROJECTS_ROOT_UUID" ON "PROJECTS" ("ROOT_UUID"); +CREATE UNIQUE INDEX "PROJECTS_UUID" ON "PROJECTS" ("UUID"); +CREATE INDEX "PROJECTS_PROJECT_UUID" ON "PROJECTS" ("PROJECT_UUID"); +CREATE INDEX "PROJECTS_MODULE_UUID" ON "PROJECTS" ("MODULE_UUID"); +CREATE INDEX "PROJECTS_QUALIFIER" ON "PROJECTS" ("QUALIFIER"); diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v74/PopulateTmpColumnsToCeQueueTest/ce_queue.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v74/PopulateTmpColumnsToCeQueueTest/ce_queue.sql new file mode 100644 index 00000000000..96cd2eab03c --- /dev/null +++ b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v74/PopulateTmpColumnsToCeQueueTest/ce_queue.sql @@ -0,0 +1,77 @@ +CREATE TABLE "CE_QUEUE" ( + "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), + "UUID" VARCHAR(40) NOT NULL, + "TASK_TYPE" VARCHAR(15) NOT NULL, + "COMPONENT_UUID" VARCHAR(40) NULL, + "TMP_COMPONENT_UUID" VARCHAR(40) NULL, + "TMP_MAIN_COMPONENT_UUID" VARCHAR(40) NULL, + "STATUS" VARCHAR(15) NOT NULL, + "SUBMITTER_UUID" VARCHAR(255) NULL, + "WORKER_UUID" VARCHAR(40) NULL, + "EXECUTION_COUNT" INTEGER NOT NULL, + "STARTED_AT" BIGINT NULL, + "CREATED_AT" BIGINT NOT NULL, + "UPDATED_AT" BIGINT NOT NULL +); +CREATE UNIQUE INDEX "CE_QUEUE_UUID" ON "CE_QUEUE" ("UUID"); +CREATE INDEX "CE_QUEUE_COMPONENT_UUID" ON "CE_QUEUE" ("COMPONENT_UUID"); +CREATE INDEX "CE_QUEUE_TMP_COMPONENT_UUID" ON "CE_QUEUE" ("TMP_COMPONENT_UUID"); +CREATE INDEX "CE_QUEUE_TMP_MAIN_CMPT_UUID" ON "CE_QUEUE" ("TMP_MAIN_COMPONENT_UUID"); +CREATE INDEX "CE_QUEUE_STATUS" ON "CE_QUEUE" ("STATUS"); + +CREATE TABLE "CE_TASK_CHARACTERISTICS" ( + "UUID" VARCHAR(40) NOT NULL, + "TASK_UUID" VARCHAR(40) NOT NULL, + "KEE" VARCHAR(50) NOT NULL, + "TEXT_VALUE" VARCHAR(4000), + + CONSTRAINT "PK_CE_TASK_CHARACTERISTICS" PRIMARY KEY ("UUID") +); +CREATE INDEX "CE_TASK_CHARACTERISTICS_TASK_UUID" ON "CE_TASK_CHARACTERISTICS" ("TASK_UUID"); + +CREATE TABLE "PROJECTS" ( + "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), + "ORGANIZATION_UUID" VARCHAR(40) NOT NULL, + "KEE" VARCHAR(400), + "UUID" VARCHAR(50) NOT NULL, + "UUID_PATH" VARCHAR(1500) NOT NULL, + "ROOT_UUID" VARCHAR(50) NOT NULL, + "PROJECT_UUID" VARCHAR(50) NOT NULL, + "MODULE_UUID" VARCHAR(50), + "MODULE_UUID_PATH" VARCHAR(1500), + "MAIN_BRANCH_PROJECT_UUID" VARCHAR(50), + "NAME" VARCHAR(2000), + "DESCRIPTION" VARCHAR(2000), + "PRIVATE" BOOLEAN NOT NULL, + "TAGS" VARCHAR(500), + "ENABLED" BOOLEAN NOT NULL DEFAULT TRUE, + "SCOPE" VARCHAR(3), + "QUALIFIER" VARCHAR(10), + "DEPRECATED_KEE" VARCHAR(400), + "PATH" VARCHAR(2000), + "LANGUAGE" VARCHAR(20), + "COPY_COMPONENT_UUID" VARCHAR(50), + "LONG_NAME" VARCHAR(2000), + "DEVELOPER_UUID" VARCHAR(50), + "CREATED_AT" TIMESTAMP, + "AUTHORIZATION_UPDATED_AT" BIGINT, + "B_CHANGED" BOOLEAN, + "B_COPY_COMPONENT_UUID" VARCHAR(50), + "B_DESCRIPTION" VARCHAR(2000), + "B_ENABLED" BOOLEAN, + "B_UUID_PATH" VARCHAR(1500), + "B_LANGUAGE" VARCHAR(20), + "B_LONG_NAME" VARCHAR(500), + "B_MODULE_UUID" VARCHAR(50), + "B_MODULE_UUID_PATH" VARCHAR(1500), + "B_NAME" VARCHAR(500), + "B_PATH" VARCHAR(2000), + "B_QUALIFIER" VARCHAR(10) +); +CREATE INDEX "PROJECTS_ORGANIZATION" ON "PROJECTS" ("ORGANIZATION_UUID"); +CREATE UNIQUE INDEX "PROJECTS_KEE" ON "PROJECTS" ("KEE"); +CREATE INDEX "PROJECTS_ROOT_UUID" ON "PROJECTS" ("ROOT_UUID"); +CREATE UNIQUE INDEX "PROJECTS_UUID" ON "PROJECTS" ("UUID"); +CREATE INDEX "PROJECTS_PROJECT_UUID" ON "PROJECTS" ("PROJECT_UUID"); +CREATE INDEX "PROJECTS_MODULE_UUID" ON "PROJECTS" ("MODULE_UUID"); +CREATE INDEX "PROJECTS_QUALIFIER" ON "PROJECTS" ("QUALIFIER"); diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v74/PopulateTmpLastKeyColumnsToCeActivityTest/ce_activity.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v74/PopulateTmpLastKeyColumnsToCeActivityTest/ce_activity.sql new file mode 100644 index 00000000000..b4e110b67e7 --- /dev/null +++ b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v74/PopulateTmpLastKeyColumnsToCeActivityTest/ce_activity.sql @@ -0,0 +1,38 @@ +CREATE TABLE "CE_ACTIVITY" ( + "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), + "UUID" VARCHAR(40) NOT NULL, + "TASK_TYPE" VARCHAR(15) NOT NULL, + "COMPONENT_UUID" VARCHAR(40) NULL, + "TMP_COMPONENT_UUID" VARCHAR(40) NULL, + "TMP_MAIN_COMPONENT_UUID" VARCHAR(40) NULL, + "ANALYSIS_UUID" VARCHAR(50) NULL, + "STATUS" VARCHAR(15) NOT NULL, + "IS_LAST" BOOLEAN NOT NULL, + "IS_LAST_KEY" VARCHAR(55) NOT NULL, + "TMP_IS_LAST" BOOLEAN, + "TMP_IS_LAST_KEY" VARCHAR(55), + "TMP_MAIN_IS_LAST" BOOLEAN, + "TMP_MAIN_IS_LAST_KEY" VARCHAR(55), + "SUBMITTER_UUID" VARCHAR(255) NULL, + "WORKER_UUID" VARCHAR(40) NULL, + "EXECUTION_COUNT" INTEGER NOT NULL, + "SUBMITTED_AT" BIGINT NOT NULL, + "STARTED_AT" BIGINT NULL, + "EXECUTED_AT" BIGINT NULL, + "CREATED_AT" BIGINT NOT NULL, + "UPDATED_AT" BIGINT NOT NULL, + "EXECUTION_TIME_MS" BIGINT NULL, + "ERROR_MESSAGE" VARCHAR(1000), + "ERROR_STACKTRACE" CLOB, + "ERROR_TYPE" VARCHAR(20) +); +CREATE UNIQUE INDEX "CE_ACTIVITY_UUID" ON "CE_ACTIVITY" ("UUID"); +CREATE INDEX "CE_ACTIVITY_COMPONENT_UUID" ON "CE_ACTIVITY" ("COMPONENT_UUID"); +CREATE INDEX "CE_ACTIVITY_TMP_CPNT_UUID" ON "CE_ACTIVITY" ("TMP_COMPONENT_UUID"); +CREATE INDEX "CE_ACTIVITY_TMP_MAIN_CPNT_UUID" ON "CE_ACTIVITY" ("TMP_MAIN_COMPONENT_UUID"); +CREATE INDEX "CE_ACTIVITY_ISLASTKEY" ON "CE_ACTIVITY" ("IS_LAST_KEY"); +CREATE INDEX "CE_ACTIVITY_ISLAST_STATUS" ON "CE_ACTIVITY" ("IS_LAST", "STATUS"); +CREATE INDEX "CE_ACTIVITY_T_ISLAST_KEY" ON "CE_ACTIVITY" ("TMP_IS_LAST_KEY"); +CREATE INDEX "CE_ACTIVITY_T_ISLAST" ON "CE_ACTIVITY" ("TMP_IS_LAST", "STATUS"); +CREATE INDEX "CE_ACTIVITY_T_MAIN_ISLAST_KEY" ON "CE_ACTIVITY" ("TMP_MAIN_IS_LAST_KEY"); +CREATE INDEX "CE_ACTIVITY_T_MAIN_ISLAST" ON "CE_ACTIVITY" ("TMP_MAIN_IS_LAST", "STATUS"); |