From 6ecfdb4160b6b113fc14abdfe0a6e43836c430c5 Mon Sep 17 00:00:00 2001 From: =?utf8?q?S=C3=A9bastien=20Lesaint?= Date: Mon, 6 Jun 2016 17:12:38 +0200 Subject: [PATCH] SONAR-7692 change table resource_index to use project uuids --- ...dd_columns_with_uuids_to_resource_index.rb | 29 +++++ ...populate_uuid_columns_of_resource_index.rb | 29 +++++ ...203_clean_orphan_rows_in_resource_index.rb | 29 +++++ ...uuid_columns_not_null_on_resource_index.rb | 31 +++++ ..._resource_index_rid_from_resource_index.rb | 29 +++++ ...206_drop_id_columns_from_resource_index.rb | 29 +++++ .../org/sonar/db/version/DatabaseVersion.java | 2 +- .../sonar/db/version/MigrationStepModule.java | 14 ++- .../sonar/db/version/VarcharColumnDef.java | 2 + .../v60/AddUuidColumnsToResourceIndex.java | 49 ++++++++ .../v60/CleanOrphanRowsInResourceIndex.java | 45 +++++++ .../v60/DropIdColumnsFromResourceIndex.java | 47 +++++++ ...MakeUuidColumnsNotNullOnResourceIndex.java | 49 ++++++++ .../PopulateUuidColumnsOfResourceIndex.java | 85 +++++++++++++ .../sonar/db/version/v60/package-info.java | 24 ++++ .../org/sonar/db/version/rows-h2.sql | 6 + .../org/sonar/db/version/schema-h2.ddl | 6 +- .../db/version/MigrationStepModuleTest.java | 2 +- .../AddUuidColumnsToResourceIndexTest.java | 80 ++++++++++++ .../CleanOrphanRowsInResourceIndexTest.java | 98 +++++++++++++++ .../DropIdColumnsFromResourceIndexTest.java | 47 +++++++ ...UuidColumnsNotNullOnResourceIndexTest.java | 92 ++++++++++++++ ...opulateUuidColumnsOfResourceIndexTest.java | 117 ++++++++++++++++++ .../old_resourceindex.sql | 9 ++ .../in_progress_resourceindex.sql | 12 ++ .../in_progress_resourceindex.sql | 12 ++ .../in_progress_resourceindex.sql | 12 ++ ...n_progress_resourceindex_with_projects.sql | 34 +++++ 28 files changed, 1014 insertions(+), 6 deletions(-) create mode 100644 server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1201_add_columns_with_uuids_to_resource_index.rb create mode 100644 server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1202_populate_uuid_columns_of_resource_index.rb create mode 100644 server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1203_clean_orphan_rows_in_resource_index.rb create mode 100644 server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1204_make_uuid_columns_not_null_on_resource_index.rb create mode 100644 server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1205_drop_resource_index_rid_from_resource_index.rb create mode 100644 server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1206_drop_id_columns_from_resource_index.rb create mode 100644 sonar-db/src/main/java/org/sonar/db/version/v60/AddUuidColumnsToResourceIndex.java create mode 100644 sonar-db/src/main/java/org/sonar/db/version/v60/CleanOrphanRowsInResourceIndex.java create mode 100644 sonar-db/src/main/java/org/sonar/db/version/v60/DropIdColumnsFromResourceIndex.java create mode 100644 sonar-db/src/main/java/org/sonar/db/version/v60/MakeUuidColumnsNotNullOnResourceIndex.java create mode 100644 sonar-db/src/main/java/org/sonar/db/version/v60/PopulateUuidColumnsOfResourceIndex.java create mode 100644 sonar-db/src/main/java/org/sonar/db/version/v60/package-info.java create mode 100644 sonar-db/src/test/java/org/sonar/db/version/v60/AddUuidColumnsToResourceIndexTest.java create mode 100644 sonar-db/src/test/java/org/sonar/db/version/v60/CleanOrphanRowsInResourceIndexTest.java create mode 100644 sonar-db/src/test/java/org/sonar/db/version/v60/DropIdColumnsFromResourceIndexTest.java create mode 100644 sonar-db/src/test/java/org/sonar/db/version/v60/MakeUuidColumnsNotNullOnResourceIndexTest.java create mode 100644 sonar-db/src/test/java/org/sonar/db/version/v60/PopulateUuidColumnsOfResourceIndexTest.java create mode 100644 sonar-db/src/test/resources/org/sonar/db/version/v60/AddUuidColumnsToResourceIndexTest/old_resourceindex.sql create mode 100644 sonar-db/src/test/resources/org/sonar/db/version/v60/CleanOrphanRowsInResourceIndexTest/in_progress_resourceindex.sql create mode 100644 sonar-db/src/test/resources/org/sonar/db/version/v60/DropIdColumnsFromResourceIndexTest/in_progress_resourceindex.sql create mode 100644 sonar-db/src/test/resources/org/sonar/db/version/v60/MakeUuidColumnsNotNullOnResourceIndexTest/in_progress_resourceindex.sql create mode 100644 sonar-db/src/test/resources/org/sonar/db/version/v60/PopulateUuidColumnsOfResourceIndexTest/in_progress_resourceindex_with_projects.sql diff --git a/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1201_add_columns_with_uuids_to_resource_index.rb b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1201_add_columns_with_uuids_to_resource_index.rb new file mode 100644 index 00000000000..a4e23b00a99 --- /dev/null +++ b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1201_add_columns_with_uuids_to_resource_index.rb @@ -0,0 +1,29 @@ +# +# SonarQube, open source software quality management tool. +# Copyright (C) 2008-2014 SonarSource +# mailto:contact AT sonarsource DOT com +# +# SonarQube is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 3 of the License, or (at your option) any later version. +# +# SonarQube is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# + +# +# SonarQube 6.0 +# +class AddColumnsWithUuidsToResourceIndex < ActiveRecord::Migration + + def self.up + execute_java_migration('org.sonar.db.version.v60.AddUuidColumnsToResourceIndex') + end +end diff --git a/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1202_populate_uuid_columns_of_resource_index.rb b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1202_populate_uuid_columns_of_resource_index.rb new file mode 100644 index 00000000000..46d47a25442 --- /dev/null +++ b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1202_populate_uuid_columns_of_resource_index.rb @@ -0,0 +1,29 @@ +# +# SonarQube, open source software quality management tool. +# Copyright (C) 2008-2014 SonarSource +# mailto:contact AT sonarsource DOT com +# +# SonarQube is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 3 of the License, or (at your option) any later version. +# +# SonarQube is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# + +# +# SonarQube 6.0 +# +class PopulateUuidColumnsOfResourceIndex < ActiveRecord::Migration + + def self.up + execute_java_migration('org.sonar.db.version.v60.PopulateUuidColumnsOfResourceIndex') + end +end diff --git a/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1203_clean_orphan_rows_in_resource_index.rb b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1203_clean_orphan_rows_in_resource_index.rb new file mode 100644 index 00000000000..fff5fe00557 --- /dev/null +++ b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1203_clean_orphan_rows_in_resource_index.rb @@ -0,0 +1,29 @@ +# +# SonarQube, open source software quality management tool. +# Copyright (C) 2008-2014 SonarSource +# mailto:contact AT sonarsource DOT com +# +# SonarQube is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 3 of the License, or (at your option) any later version. +# +# SonarQube is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# + +# +# SonarQube 6.0 +# +class CleanOrphanRowsInResourceIndex < ActiveRecord::Migration + + def self.up + execute_java_migration('org.sonar.db.version.v60.CleanOrphanRowsInResourceIndex') + end +end diff --git a/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1204_make_uuid_columns_not_null_on_resource_index.rb b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1204_make_uuid_columns_not_null_on_resource_index.rb new file mode 100644 index 00000000000..e1e9d7dd299 --- /dev/null +++ b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1204_make_uuid_columns_not_null_on_resource_index.rb @@ -0,0 +1,31 @@ +# +# SonarQube, open source software quality management tool. +# Copyright (C) 2008-2014 SonarSource +# mailto:contact AT sonarsource DOT com +# +# SonarQube is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 3 of the License, or (at your option) any later version. +# +# SonarQube is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# + +# +# SonarQube 6.0 +# +class MakeUuidColumnsNotNullOnResourceIndex < ActiveRecord::Migration + + def self.up + execute_java_migration('org.sonar.db.version.v60.MakeUuidColumnsNotNullOnResourceIndex') + + add_index :resource_index, :component_uuid, :name => 'resource_index_component' + end +end diff --git a/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1205_drop_resource_index_rid_from_resource_index.rb b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1205_drop_resource_index_rid_from_resource_index.rb new file mode 100644 index 00000000000..e44007e7046 --- /dev/null +++ b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1205_drop_resource_index_rid_from_resource_index.rb @@ -0,0 +1,29 @@ +# +# SonarQube, open source software quality management tool. +# Copyright (C) 2008-2014 SonarSource +# mailto:contact AT sonarsource DOT com +# +# SonarQube is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 3 of the License, or (at your option) any later version. +# +# SonarQube is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# + +# +# SonarQube 6.0 +# +class DropResourceIndexRidFromResourceIndex < ActiveRecord::Migration + + def self.up + remove_index :resource_index, :name => 'resource_index_rid' + end +end diff --git a/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1206_drop_id_columns_from_resource_index.rb b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1206_drop_id_columns_from_resource_index.rb new file mode 100644 index 00000000000..08a0ebd9b17 --- /dev/null +++ b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1206_drop_id_columns_from_resource_index.rb @@ -0,0 +1,29 @@ +# +# SonarQube, open source software quality management tool. +# Copyright (C) 2008-2014 SonarSource +# mailto:contact AT sonarsource DOT com +# +# SonarQube is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 3 of the License, or (at your option) any later version. +# +# SonarQube is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# + +# +# SonarQube 6.0 +# +class DropIdColumnsFromResourceIndex < ActiveRecord::Migration + + def self.up + execute_java_migration('org.sonar.db.version.v60.DropIdColumnsFromResourceIndex') + end +end diff --git a/sonar-db/src/main/java/org/sonar/db/version/DatabaseVersion.java b/sonar-db/src/main/java/org/sonar/db/version/DatabaseVersion.java index c6d0c3ea08f..92a8efd43bb 100644 --- a/sonar-db/src/main/java/org/sonar/db/version/DatabaseVersion.java +++ b/sonar-db/src/main/java/org/sonar/db/version/DatabaseVersion.java @@ -30,7 +30,7 @@ import org.sonar.db.MyBatis; public class DatabaseVersion { - public static final int LAST_VERSION = 1_200; + public static final int LAST_VERSION = 1_206; /** * The minimum supported version which can be upgraded. Lower diff --git a/sonar-db/src/main/java/org/sonar/db/version/MigrationStepModule.java b/sonar-db/src/main/java/org/sonar/db/version/MigrationStepModule.java index 2dcaea78e4c..31a7dfe683e 100644 --- a/sonar-db/src/main/java/org/sonar/db/version/MigrationStepModule.java +++ b/sonar-db/src/main/java/org/sonar/db/version/MigrationStepModule.java @@ -83,6 +83,11 @@ import org.sonar.db.version.v55.FeedRulesLongDateColumns; import org.sonar.db.version.v55.FeedRulesTypes; import org.sonar.db.version.v56.FixLengthOfIssuesMessageOnOracle; import org.sonar.db.version.v56.FixTypeOfRuleTypeOnMysql; +import org.sonar.db.version.v60.AddUuidColumnsToResourceIndex; +import org.sonar.db.version.v60.CleanOrphanRowsInResourceIndex; +import org.sonar.db.version.v60.DropIdColumnsFromResourceIndex; +import org.sonar.db.version.v60.MakeUuidColumnsNotNullOnResourceIndex; +import org.sonar.db.version.v60.PopulateUuidColumnsOfResourceIndex; public class MigrationStepModule extends Module { @Override @@ -165,6 +170,13 @@ public class MigrationStepModule extends Module { // 5.6 FixTypeOfRuleTypeOnMysql.class, - FixLengthOfIssuesMessageOnOracle.class); + FixLengthOfIssuesMessageOnOracle.class, + + // 6.0 + AddUuidColumnsToResourceIndex.class, + PopulateUuidColumnsOfResourceIndex.class, + CleanOrphanRowsInResourceIndex.class, + MakeUuidColumnsNotNullOnResourceIndex.class, + DropIdColumnsFromResourceIndex.class); } } diff --git a/sonar-db/src/main/java/org/sonar/db/version/VarcharColumnDef.java b/sonar-db/src/main/java/org/sonar/db/version/VarcharColumnDef.java index 83052bb83d0..71c77a0cd1f 100644 --- a/sonar-db/src/main/java/org/sonar/db/version/VarcharColumnDef.java +++ b/sonar-db/src/main/java/org/sonar/db/version/VarcharColumnDef.java @@ -31,6 +31,8 @@ import static org.sonar.db.version.ColumnDefValidation.validateColumnName; * Used to define VARCHAR column */ public class VarcharColumnDef extends AbstractColumnDef { + public static final int UUID_VARCHAR_SIZE = 50; + private final int columnSize; private VarcharColumnDef(Builder builder) { diff --git a/sonar-db/src/main/java/org/sonar/db/version/v60/AddUuidColumnsToResourceIndex.java b/sonar-db/src/main/java/org/sonar/db/version/v60/AddUuidColumnsToResourceIndex.java new file mode 100644 index 00000000000..784db311490 --- /dev/null +++ b/sonar-db/src/main/java/org/sonar/db/version/v60/AddUuidColumnsToResourceIndex.java @@ -0,0 +1,49 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.db.version.v60; + +import java.sql.SQLException; +import org.sonar.db.Database; +import org.sonar.db.version.AddColumnsBuilder; +import org.sonar.db.version.DdlChange; + +import static org.sonar.db.version.VarcharColumnDef.UUID_VARCHAR_SIZE; +import static org.sonar.db.version.VarcharColumnDef.newVarcharColumnDefBuilder; + +public class AddUuidColumnsToResourceIndex extends DdlChange { + + private static final String TABLE_RESOURCE_INDEX = "resource_index"; + + private final Database db; + + public AddUuidColumnsToResourceIndex(Database db) { + super(db); + this.db = db; + } + + @Override + public void execute(Context context) throws SQLException { + context.execute(new AddColumnsBuilder(db.getDialect(), TABLE_RESOURCE_INDEX) + .addColumn(newVarcharColumnDefBuilder().setColumnName("component_uuid").setLimit(UUID_VARCHAR_SIZE).setIsNullable(true).build()) + .addColumn(newVarcharColumnDefBuilder().setColumnName("root_component_uuid").setLimit(UUID_VARCHAR_SIZE).setIsNullable(true).build()) + .build()); + } + +} diff --git a/sonar-db/src/main/java/org/sonar/db/version/v60/CleanOrphanRowsInResourceIndex.java b/sonar-db/src/main/java/org/sonar/db/version/v60/CleanOrphanRowsInResourceIndex.java new file mode 100644 index 00000000000..e0594483c21 --- /dev/null +++ b/sonar-db/src/main/java/org/sonar/db/version/v60/CleanOrphanRowsInResourceIndex.java @@ -0,0 +1,45 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.db.version.v60; + +import java.sql.SQLException; +import org.sonar.db.Database; +import org.sonar.db.version.BaseDataChange; +import org.sonar.db.version.MassUpdate; + +public class CleanOrphanRowsInResourceIndex extends BaseDataChange { + + public CleanOrphanRowsInResourceIndex(Database db) { + super(db); + } + + @Override + public void execute(Context context) throws SQLException { + MassUpdate massUpdate = context.prepareMassUpdate(); + massUpdate.select("SELECT ri.id, ri.resource_id, ri.root_project_id from resource_index ri where ri.component_uuid is null or ri.root_component_uuid is null"); + massUpdate.update("DELETE from resource_index WHERE id=?"); + massUpdate.rowPluralName("resource index entries"); + massUpdate.execute((row, update) -> { + update.setLong(1, row.getLong(1)); + return true; + }); + } + +} diff --git a/sonar-db/src/main/java/org/sonar/db/version/v60/DropIdColumnsFromResourceIndex.java b/sonar-db/src/main/java/org/sonar/db/version/v60/DropIdColumnsFromResourceIndex.java new file mode 100644 index 00000000000..f7fe94c38e0 --- /dev/null +++ b/sonar-db/src/main/java/org/sonar/db/version/v60/DropIdColumnsFromResourceIndex.java @@ -0,0 +1,47 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.db.version.v60; + +import java.sql.SQLException; +import org.sonar.db.Database; +import org.sonar.db.version.DdlChange; +import org.sonar.db.version.DropColumnsBuilder; + +public class DropIdColumnsFromResourceIndex extends DdlChange { + + private static final String TABLE_RESOURCE_INDEX = "resource_index"; + + private final Database db; + + public DropIdColumnsFromResourceIndex(Database db) { + super(db); + this.db = db; + } + + @Override + public void execute(Context context) throws SQLException { + context.execute( + new DropColumnsBuilder( + db.getDialect(), TABLE_RESOURCE_INDEX, + "resource_id", "root_project_id") + .build()); + } + +} diff --git a/sonar-db/src/main/java/org/sonar/db/version/v60/MakeUuidColumnsNotNullOnResourceIndex.java b/sonar-db/src/main/java/org/sonar/db/version/v60/MakeUuidColumnsNotNullOnResourceIndex.java new file mode 100644 index 00000000000..16e01b30323 --- /dev/null +++ b/sonar-db/src/main/java/org/sonar/db/version/v60/MakeUuidColumnsNotNullOnResourceIndex.java @@ -0,0 +1,49 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.db.version.v60; + +import java.sql.SQLException; +import org.sonar.db.Database; +import org.sonar.db.version.AlterColumnsTypeBuilder; +import org.sonar.db.version.DdlChange; + +import static org.sonar.db.version.VarcharColumnDef.UUID_VARCHAR_SIZE; +import static org.sonar.db.version.VarcharColumnDef.newVarcharColumnDefBuilder; + +public class MakeUuidColumnsNotNullOnResourceIndex extends DdlChange { + + private static final String TABLE_RESOURCE_INDEX = "resource_index"; + + private final Database db; + + public MakeUuidColumnsNotNullOnResourceIndex(Database db) { + super(db); + this.db = db; + } + + @Override + public void execute(Context context) throws SQLException { + context.execute(new AlterColumnsTypeBuilder(db.getDialect(), TABLE_RESOURCE_INDEX) + .updateColumn(newVarcharColumnDefBuilder().setColumnName("component_uuid").setLimit(UUID_VARCHAR_SIZE).setIsNullable(false).build()) + .updateColumn(newVarcharColumnDefBuilder().setColumnName("root_component_uuid").setLimit(UUID_VARCHAR_SIZE).setIsNullable(false).build()) + .build()); + } + +} diff --git a/sonar-db/src/main/java/org/sonar/db/version/v60/PopulateUuidColumnsOfResourceIndex.java b/sonar-db/src/main/java/org/sonar/db/version/v60/PopulateUuidColumnsOfResourceIndex.java new file mode 100644 index 00000000000..e5be59b5f48 --- /dev/null +++ b/sonar-db/src/main/java/org/sonar/db/version/v60/PopulateUuidColumnsOfResourceIndex.java @@ -0,0 +1,85 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.db.version.v60; + +import java.sql.SQLException; +import java.util.HashMap; +import java.util.Map; +import org.sonar.db.Database; +import org.sonar.db.version.BaseDataChange; +import org.sonar.db.version.MassUpdate; +import org.sonar.db.version.Select; +import org.sonar.db.version.SqlStatement; + +public class PopulateUuidColumnsOfResourceIndex extends BaseDataChange { + + public PopulateUuidColumnsOfResourceIndex(Database db) { + super(db); + } + + @Override + public void execute(Context context) throws SQLException { + Map componentUuidById = buildComponentUuidMap(context); + if (componentUuidById.isEmpty()) { + return; + } + + populateUuidColumns(context, componentUuidById); + } + + private Map buildComponentUuidMap(Context context) throws SQLException { + Map componentUuidById = new HashMap<>(); + context.prepareSelect("select distinct p.id, p.uuid from projects p" + + " join resource_index ri1 on ri1.resource_id = p.id and ri1.component_uuid is null") + .scroll(row -> componentUuidById.put(row.getLong(1), row.getString(2))); + context.prepareSelect("select distinct p.id, p.uuid from projects p" + + " join resource_index ri2 on ri2.root_project_id = p.id and ri2.root_component_uuid is null") + .scroll(row -> componentUuidById.put(row.getLong(1), row.getString(2))); + return componentUuidById; + } + + private void populateUuidColumns(Context context, Map componentUuidById) throws SQLException { + MassUpdate massUpdate = context.prepareMassUpdate(); + massUpdate.select("SELECT ri.id, ri.resource_id, ri.root_project_id from resource_index ri where ri.component_uuid is null or ri.root_component_uuid is null"); + massUpdate.update("UPDATE resource_index SET component_uuid=?, root_component_uuid=? WHERE id=?"); + massUpdate.rowPluralName("resource index entries"); + massUpdate.execute((row, update) -> this.handle(componentUuidById, row, update)); + } + + public boolean handle(Map componentUuidById, Select.Row row, SqlStatement update) throws SQLException { + long id = row.getLong(1); + long componentId = row.getLong(2); + long rootProjectId = row.getLong(3); + + String componentUuid = componentUuidById.get(componentId); + String rootComponentUuid = componentUuidById.get(rootProjectId); + + if (componentUuid == null && rootComponentUuid == null) { + return false; + } + + update.setString(1, componentUuid); + update.setString(2, rootComponentUuid); + update.setLong(3, id); + + return true; + } + +} diff --git a/sonar-db/src/main/java/org/sonar/db/version/v60/package-info.java b/sonar-db/src/main/java/org/sonar/db/version/v60/package-info.java new file mode 100644 index 00000000000..4b742e678a6 --- /dev/null +++ b/sonar-db/src/main/java/org/sonar/db/version/v60/package-info.java @@ -0,0 +1,24 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +@ParametersAreNonnullByDefault +package org.sonar.db.version.v60; + +import javax.annotation.ParametersAreNonnullByDefault; + diff --git a/sonar-db/src/main/resources/org/sonar/db/version/rows-h2.sql b/sonar-db/src/main/resources/org/sonar/db/version/rows-h2.sql index c7c52e0b332..aa808f28acb 100644 --- a/sonar-db/src/main/resources/org/sonar/db/version/rows-h2.sql +++ b/sonar-db/src/main/resources/org/sonar/db/version/rows-h2.sql @@ -407,6 +407,12 @@ INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1151'); INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1152'); INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1200'); +INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1201'); +INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1202'); +INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1203'); +INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1204'); +INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1205'); +INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1206'); INSERT INTO USERS(ID, LOGIN, NAME, EMAIL, EXTERNAL_IDENTITY, EXTERNAL_IDENTITY_PROVIDER, USER_LOCAL, CRYPTED_PASSWORD, SALT, CREATED_AT, UPDATED_AT, REMEMBER_TOKEN, REMEMBER_TOKEN_EXPIRES_AT) VALUES (1, 'admin', 'Administrator', '', 'admin', 'sonarqube', true, 'a373a0e667abb2604c1fd571eb4ad47fe8cc0878', '48bc4b0d93179b5103fd3885ea9119498e9d161b', '1418215735482', '1418215735482', null, null); ALTER TABLE USERS ALTER COLUMN ID RESTART WITH 2; diff --git a/sonar-db/src/main/resources/org/sonar/db/version/schema-h2.ddl b/sonar-db/src/main/resources/org/sonar/db/version/schema-h2.ddl index d888aacbd41..66739471b15 100644 --- a/sonar-db/src/main/resources/org/sonar/db/version/schema-h2.ddl +++ b/sonar-db/src/main/resources/org/sonar/db/version/schema-h2.ddl @@ -350,8 +350,8 @@ CREATE TABLE "RESOURCE_INDEX" ( "KEE" VARCHAR(400) NOT NULL, "POSITION" INTEGER NOT NULL, "NAME_SIZE" INTEGER NOT NULL, - "RESOURCE_ID" INTEGER NOT NULL, - "ROOT_PROJECT_ID" INTEGER NOT NULL, + "COMPONENT_UUID" VARCHAR(50) NOT NULL, + "ROOT_COMPONENT_UUID" VARCHAR(50) NOT NULL, "QUALIFIER" VARCHAR(10) NOT NULL ); @@ -614,7 +614,7 @@ CREATE INDEX "PROJECTS_QUALIFIER" ON "PROJECTS" ("QUALIFIER"); CREATE INDEX "RESOURCE_INDEX_KEY" ON "RESOURCE_INDEX" ("KEE"); -CREATE INDEX "RESOURCE_INDEX_RID" ON "RESOURCE_INDEX" ("RESOURCE_ID"); +CREATE INDEX "RESOURCE_INDEX_COMPONENT" ON "RESOURCE_INDEX" ("COMPONENT_UUID"); CREATE UNIQUE INDEX "UNIQ_AUTHOR_LOGINS" ON "AUTHORS" ("LOGIN"); diff --git a/sonar-db/src/test/java/org/sonar/db/version/MigrationStepModuleTest.java b/sonar-db/src/test/java/org/sonar/db/version/MigrationStepModuleTest.java index 91bda96d3de..b5d86617502 100644 --- a/sonar-db/src/test/java/org/sonar/db/version/MigrationStepModuleTest.java +++ b/sonar-db/src/test/java/org/sonar/db/version/MigrationStepModuleTest.java @@ -29,6 +29,6 @@ public class MigrationStepModuleTest { public void verify_count_of_added_MigrationStep_types() { ComponentContainer container = new ComponentContainer(); new MigrationStepModule().configure(container); - assertThat(container.size()).isEqualTo(65); + assertThat(container.size()).isEqualTo(70); } } diff --git a/sonar-db/src/test/java/org/sonar/db/version/v60/AddUuidColumnsToResourceIndexTest.java b/sonar-db/src/test/java/org/sonar/db/version/v60/AddUuidColumnsToResourceIndexTest.java new file mode 100644 index 00000000000..9fcd6a44fa7 --- /dev/null +++ b/sonar-db/src/test/java/org/sonar/db/version/v60/AddUuidColumnsToResourceIndexTest.java @@ -0,0 +1,80 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.db.version.v60; + +import java.sql.SQLException; +import java.sql.Types; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.sonar.api.utils.System2; +import org.sonar.db.DbTester; + +import static java.lang.String.valueOf; + +public class AddUuidColumnsToResourceIndexTest { + + @Rule + public DbTester db = DbTester.createForSchema(System2.INSTANCE, AddUuidColumnsToResourceIndexTest.class, "old_resourceindex.sql"); + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + private AddUuidColumnsToResourceIndex underTest = new AddUuidColumnsToResourceIndex(db.database()); + + @Test + public void migration_adds_columns_to_empty_table() throws SQLException { + underTest.execute(); + + verifyAddedColumns(); + } + + @Test + public void migration_adds_columns_to_populated_table() throws SQLException { + for (int i = 0; i < 9; i++) { + db.executeInsert( + "resource_index", + "KEE", "key_" + i, + "POSITION", valueOf(i), + "NAME_SIZE", valueOf(i + 1), + "RESOURCE_ID", valueOf(i + 10), + "ROOT_PROJECT_ID", valueOf(i + 20), + "QUALIFIER", (i % 2 == 0 ? "FILE" : "PROJECT")); + } + db.commit(); + + underTest.execute(); + + verifyAddedColumns(); + } + + private void verifyAddedColumns() { + db.assertColumnDefinition("resource_index", "component_uuid", Types.VARCHAR, 50, true); + db.assertColumnDefinition("resource_index", "root_component_uuid", Types.VARCHAR, 50, true); + } + + @Test + public void migration_is_not_reentrant() throws SQLException { + underTest.execute(); + + expectedException.expect(IllegalStateException.class); + expectedException.expectMessage("Fail to execute "); + underTest.execute(); + } +} diff --git a/sonar-db/src/test/java/org/sonar/db/version/v60/CleanOrphanRowsInResourceIndexTest.java b/sonar-db/src/test/java/org/sonar/db/version/v60/CleanOrphanRowsInResourceIndexTest.java new file mode 100644 index 00000000000..ec42a1343d0 --- /dev/null +++ b/sonar-db/src/test/java/org/sonar/db/version/v60/CleanOrphanRowsInResourceIndexTest.java @@ -0,0 +1,98 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.db.version.v60; + +import java.sql.SQLException; +import java.util.List; +import java.util.stream.Collectors; +import org.junit.Rule; +import org.junit.Test; +import org.sonar.api.utils.System2; +import org.sonar.db.DbTester; + +import static java.lang.String.valueOf; +import static org.assertj.core.api.Assertions.assertThat; + +public class CleanOrphanRowsInResourceIndexTest { + + @Rule + public DbTester db = DbTester.createForSchema(System2.INSTANCE, CleanOrphanRowsInResourceIndexTest.class, + "in_progress_resourceindex.sql"); + + private CleanOrphanRowsInResourceIndex underTest = new CleanOrphanRowsInResourceIndex(db.database()); + + @Test + public void migration_has_no_effect_on_empty_table() throws SQLException { + underTest.execute(); + + assertThat(db.countRowsOfTable("resource_index")).isEqualTo(0); + } + + @Test + public void migration_deletes_any_row_with_a_null_uuid() throws SQLException { + insertResourceIndex(1, true, true); + insertResourceIndex(2, false, false); + insertResourceIndex(3, true, false); + insertResourceIndex(4, false, true); + insertResourceIndex(5, true, true); + db.commit(); + + underTest.execute(); + + assertThat(idsOfRowsInResourceIndex()).containsOnly(1l, 5l); + } + + @Test + public void migration_is_reentrant() throws SQLException { + insertResourceIndex(1, true, true); + insertResourceIndex(2, false, false); + + underTest.execute(); + + assertThat(idsOfRowsInResourceIndex()).containsOnly(1l); + + underTest.execute(); + + assertThat(idsOfRowsInResourceIndex()).containsOnly(1l); + } + + private List idsOfRowsInResourceIndex() { + return db.select("select ID from resource_index").stream().map(map -> (Long) map.get("ID")).collect(Collectors.toList()); + } + + private void insertResourceIndex(long id, boolean hasComponentUiid, boolean hasRootComponentUuid) { + db.executeInsert( + "resource_index", + "ID", valueOf(id), + "KEE", "key_" + id, + "POSITION", valueOf(id + 100), + "NAME_SIZE", valueOf(id + 1000), + "RESOURCE_ID", valueOf(id + 300), + "ROOT_PROJECT_ID", valueOf(id + 4000), + "QUALIFIER", "PROJECT"); + + if (hasComponentUiid) { + db.executeUpdateSql("update resource_index set COMPONENT_UUID=? where id=?", "uuid_" + id, valueOf(id)); + } + if (hasRootComponentUuid) { + db.executeUpdateSql("update resource_index set ROOT_COMPONENT_UUID=? where id=?", "root_uuid_" + id, valueOf(id)); + } + } +} diff --git a/sonar-db/src/test/java/org/sonar/db/version/v60/DropIdColumnsFromResourceIndexTest.java b/sonar-db/src/test/java/org/sonar/db/version/v60/DropIdColumnsFromResourceIndexTest.java new file mode 100644 index 00000000000..c28670e7a7d --- /dev/null +++ b/sonar-db/src/test/java/org/sonar/db/version/v60/DropIdColumnsFromResourceIndexTest.java @@ -0,0 +1,47 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.db.version.v60; + +import java.sql.SQLException; +import org.junit.Test; +import org.sonar.db.Database; +import org.sonar.db.dialect.PostgreSql; +import org.sonar.db.version.DdlChange; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +public class DropIdColumnsFromResourceIndexTest { + + private Database database = mock(Database.class); + + private DropIdColumnsFromResourceIndex underTest = new DropIdColumnsFromResourceIndex(database); + + @Test + public void verify_generated_sql_on_postgresql() throws SQLException { + when(database.getDialect()).thenReturn(new PostgreSql()); + + DdlChange.Context context = mock(DdlChange.Context.class); + underTest.execute(context); + + verify(context).execute("ALTER TABLE resource_index DROP COLUMN resource_id, DROP COLUMN root_project_id"); + } +} diff --git a/sonar-db/src/test/java/org/sonar/db/version/v60/MakeUuidColumnsNotNullOnResourceIndexTest.java b/sonar-db/src/test/java/org/sonar/db/version/v60/MakeUuidColumnsNotNullOnResourceIndexTest.java new file mode 100644 index 00000000000..f60e3085763 --- /dev/null +++ b/sonar-db/src/test/java/org/sonar/db/version/v60/MakeUuidColumnsNotNullOnResourceIndexTest.java @@ -0,0 +1,92 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.db.version.v60; + +import java.sql.SQLException; +import java.sql.Types; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.sonar.api.utils.System2; +import org.sonar.db.DbTester; + +import static java.lang.String.valueOf; + +public class MakeUuidColumnsNotNullOnResourceIndexTest { + + @Rule + public DbTester db = DbTester.createForSchema(System2.INSTANCE, MakeUuidColumnsNotNullOnResourceIndexTest.class, + "in_progress_resourceindex.sql"); + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + private MakeUuidColumnsNotNullOnResourceIndex underTest = new MakeUuidColumnsNotNullOnResourceIndex(db.database()); + + @Test + public void migration_sets_uuid_columns_not_nullable_on_empty_table() throws SQLException { + underTest.execute(); + + verifyColumnDefinitions(); + } + + @Test + public void migration_sets_uuid_columns_not_nullable_on_populated_table() throws SQLException { + insertResourceIndex(1, true, true); + insertResourceIndex(2, true, true); + + underTest.execute(); + + verifyColumnDefinitions(); + } + + @Test + public void migration_fails_if_some_uuid_columns_are_null() throws SQLException { + insertResourceIndex(1, false, true); + + expectedException.expect(IllegalStateException.class); + expectedException.expectMessage("Fail to execute"); + + underTest.execute(); + } + + private void verifyColumnDefinitions() { + db.assertColumnDefinition("resource_index", "component_uuid", Types.VARCHAR, 50, false); + db.assertColumnDefinition("resource_index", "root_component_uuid", Types.VARCHAR, 50, false); + } + + private void insertResourceIndex(long id, boolean hasComponentUiid, boolean hasRootComponentUuid) { + db.executeInsert( + "resource_index", + "ID", valueOf(id), + "KEE", "key_" + id, + "POSITION", valueOf(id + 100), + "NAME_SIZE", valueOf(id + 1000), + "RESOURCE_ID", valueOf(id + 300), + "ROOT_PROJECT_ID", valueOf(id + 4000), + "QUALIFIER", "PROJECT"); + + if (hasComponentUiid) { + db.executeUpdateSql("update resource_index set COMPONENT_UUID=? where id=?", "uuid_" + id, valueOf(id)); + } + if (hasRootComponentUuid) { + db.executeUpdateSql("update resource_index set ROOT_COMPONENT_UUID=? where id=?", "root_uuid_" + id, valueOf(id)); + } + } +} diff --git a/sonar-db/src/test/java/org/sonar/db/version/v60/PopulateUuidColumnsOfResourceIndexTest.java b/sonar-db/src/test/java/org/sonar/db/version/v60/PopulateUuidColumnsOfResourceIndexTest.java new file mode 100644 index 00000000000..b5b24d27e9e --- /dev/null +++ b/sonar-db/src/test/java/org/sonar/db/version/v60/PopulateUuidColumnsOfResourceIndexTest.java @@ -0,0 +1,117 @@ +/* + * SonarQube + * Copyright (C) 2009-2016 SonarSource SA + * mailto:contact AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.db.version.v60; + +import java.sql.SQLException; +import java.util.List; +import java.util.Map; +import javax.annotation.Nullable; +import org.junit.Rule; +import org.junit.Test; +import org.sonar.api.utils.System2; +import org.sonar.db.DbTester; + +import static java.lang.String.valueOf; +import static org.assertj.core.api.Assertions.assertThat; + +public class PopulateUuidColumnsOfResourceIndexTest { + + @Rule + public DbTester db = DbTester.createForSchema(System2.INSTANCE, PopulateUuidColumnsOfResourceIndexTest.class, + "in_progress_resourceindex_with_projects.sql"); + + private PopulateUuidColumnsOfResourceIndex underTest = new PopulateUuidColumnsOfResourceIndex(db.database()); + + @Test + public void migration_has_no_effect_on_empty_tables() throws SQLException { + underTest.execute(); + + assertThat(db.countRowsOfTable("resource_index")).isEqualTo(0); + assertThat(db.countRowsOfTable("projects")).isEqualTo(0); + } + + @Test + public void migration_updates_uuid_columns_with_values_from_table_projects_when_they_exist() throws SQLException { + String uuid1 = insertComponent(40); + String uuid2 = insertComponent(50); + String uuid3 = insertComponent(60); + String uuid4 = insertComponent(70); + + insertResourceIndex(1, 40, 50); + insertResourceIndex(2, 60, 70); + insertResourceIndex(3, 90, 70); // 90 does not exist + insertResourceIndex(4, 40, 100); // 100 does not exist + insertResourceIndex(5, 110, 100); // 110 and 100 do not exist + db.commit(); + + underTest.execute(); + + verifyResourceIndex(1, 40, uuid1, 50, uuid2); + verifyResourceIndex(2, 60, uuid3, 70, uuid4); + verifyResourceIndex(3, 90, null, 70, uuid4); + verifyResourceIndex(4, 40, uuid1, 100, null); + verifyResourceIndex(5, 110, null, 100, null); + } + + @Test + public void migration_is_reentrant() throws SQLException { + String uuid1 = insertComponent(40); + String uuid2 = insertComponent(50); + insertResourceIndex(1, 40, 50); + + underTest.execute(); + verifyResourceIndex(1, 40, uuid1, 50, uuid2); + + underTest.execute(); + verifyResourceIndex(1, 40, uuid1, 50, uuid2); + + } + + private void verifyResourceIndex(long id, long resourceId, @Nullable String componentUuid, long rootProjectId, @Nullable String rootComponentUuid) { + List> rows = db.select("select RESOURCE_ID, COMPONENT_UUID, ROOT_PROJECT_ID, ROOT_COMPONENT_UUID from resource_index where ID=" + id); + assertThat(rows).hasSize(1); + Map row = rows.get(0); + assertThat(row.get("RESOURCE_ID")).isEqualTo(resourceId); + assertThat(row.get("COMPONENT_UUID")).isEqualTo(componentUuid); + assertThat(row.get("ROOT_PROJECT_ID")).isEqualTo(rootProjectId); + assertThat(row.get("ROOT_COMPONENT_UUID")).isEqualTo(rootComponentUuid); + } + + private String insertComponent(long id) { + String uuid = "uuid_" + id; + db.executeInsert( + "projects", + "ID", valueOf(id), + "UUID", uuid); + return uuid; + } + + private void insertResourceIndex(long id, long resourceId, long rootProjectId) { + db.executeInsert( + "resource_index", + "ID", valueOf(id), + "KEE", "key_" + id, + "POSITION", valueOf(id + 100), + "NAME_SIZE", valueOf(id + 1000), + "RESOURCE_ID", valueOf(resourceId), + "ROOT_PROJECT_ID", valueOf(rootProjectId), + "QUALIFIER", "PROJECT"); + } +} diff --git a/sonar-db/src/test/resources/org/sonar/db/version/v60/AddUuidColumnsToResourceIndexTest/old_resourceindex.sql b/sonar-db/src/test/resources/org/sonar/db/version/v60/AddUuidColumnsToResourceIndexTest/old_resourceindex.sql new file mode 100644 index 00000000000..6037299d5ac --- /dev/null +++ b/sonar-db/src/test/resources/org/sonar/db/version/v60/AddUuidColumnsToResourceIndexTest/old_resourceindex.sql @@ -0,0 +1,9 @@ +CREATE TABLE "RESOURCE_INDEX" ( + "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), + "KEE" VARCHAR(400) NOT NULL, + "POSITION" INTEGER NOT NULL, + "NAME_SIZE" INTEGER NOT NULL, + "RESOURCE_ID" INTEGER NOT NULL, + "ROOT_PROJECT_ID" INTEGER NOT NULL, + "QUALIFIER" VARCHAR(10) NOT NULL +); diff --git a/sonar-db/src/test/resources/org/sonar/db/version/v60/CleanOrphanRowsInResourceIndexTest/in_progress_resourceindex.sql b/sonar-db/src/test/resources/org/sonar/db/version/v60/CleanOrphanRowsInResourceIndexTest/in_progress_resourceindex.sql new file mode 100644 index 00000000000..aab2040b1ed --- /dev/null +++ b/sonar-db/src/test/resources/org/sonar/db/version/v60/CleanOrphanRowsInResourceIndexTest/in_progress_resourceindex.sql @@ -0,0 +1,12 @@ +CREATE TABLE "RESOURCE_INDEX" ( + "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), + "KEE" VARCHAR(400) NOT NULL, + "POSITION" INTEGER NOT NULL, + "NAME_SIZE" INTEGER NOT NULL, + "RESOURCE_ID" INTEGER NOT NULL, + "ROOT_PROJECT_ID" INTEGER NOT NULL, + "QUALIFIER" VARCHAR(10) NOT NULL, + "COMPONENT_UUID" VARCHAR(50), + "ROOT_COMPONENT_UUID" VARCHAR(50) +); + diff --git a/sonar-db/src/test/resources/org/sonar/db/version/v60/DropIdColumnsFromResourceIndexTest/in_progress_resourceindex.sql b/sonar-db/src/test/resources/org/sonar/db/version/v60/DropIdColumnsFromResourceIndexTest/in_progress_resourceindex.sql new file mode 100644 index 00000000000..aab2040b1ed --- /dev/null +++ b/sonar-db/src/test/resources/org/sonar/db/version/v60/DropIdColumnsFromResourceIndexTest/in_progress_resourceindex.sql @@ -0,0 +1,12 @@ +CREATE TABLE "RESOURCE_INDEX" ( + "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), + "KEE" VARCHAR(400) NOT NULL, + "POSITION" INTEGER NOT NULL, + "NAME_SIZE" INTEGER NOT NULL, + "RESOURCE_ID" INTEGER NOT NULL, + "ROOT_PROJECT_ID" INTEGER NOT NULL, + "QUALIFIER" VARCHAR(10) NOT NULL, + "COMPONENT_UUID" VARCHAR(50), + "ROOT_COMPONENT_UUID" VARCHAR(50) +); + diff --git a/sonar-db/src/test/resources/org/sonar/db/version/v60/MakeUuidColumnsNotNullOnResourceIndexTest/in_progress_resourceindex.sql b/sonar-db/src/test/resources/org/sonar/db/version/v60/MakeUuidColumnsNotNullOnResourceIndexTest/in_progress_resourceindex.sql new file mode 100644 index 00000000000..aab2040b1ed --- /dev/null +++ b/sonar-db/src/test/resources/org/sonar/db/version/v60/MakeUuidColumnsNotNullOnResourceIndexTest/in_progress_resourceindex.sql @@ -0,0 +1,12 @@ +CREATE TABLE "RESOURCE_INDEX" ( + "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), + "KEE" VARCHAR(400) NOT NULL, + "POSITION" INTEGER NOT NULL, + "NAME_SIZE" INTEGER NOT NULL, + "RESOURCE_ID" INTEGER NOT NULL, + "ROOT_PROJECT_ID" INTEGER NOT NULL, + "QUALIFIER" VARCHAR(10) NOT NULL, + "COMPONENT_UUID" VARCHAR(50), + "ROOT_COMPONENT_UUID" VARCHAR(50) +); + diff --git a/sonar-db/src/test/resources/org/sonar/db/version/v60/PopulateUuidColumnsOfResourceIndexTest/in_progress_resourceindex_with_projects.sql b/sonar-db/src/test/resources/org/sonar/db/version/v60/PopulateUuidColumnsOfResourceIndexTest/in_progress_resourceindex_with_projects.sql new file mode 100644 index 00000000000..2551ca942d0 --- /dev/null +++ b/sonar-db/src/test/resources/org/sonar/db/version/v60/PopulateUuidColumnsOfResourceIndexTest/in_progress_resourceindex_with_projects.sql @@ -0,0 +1,34 @@ +CREATE TABLE "RESOURCE_INDEX" ( + "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), + "KEE" VARCHAR(400) NOT NULL, + "POSITION" INTEGER NOT NULL, + "NAME_SIZE" INTEGER NOT NULL, + "RESOURCE_ID" INTEGER NOT NULL, + "ROOT_PROJECT_ID" INTEGER NOT NULL, + "QUALIFIER" VARCHAR(10) NOT NULL, + "COMPONENT_UUID" VARCHAR(50), + "ROOT_COMPONENT_UUID" VARCHAR(50) +); + +CREATE TABLE "PROJECTS" ( + "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1), + "KEE" VARCHAR(400), + "ROOT_ID" INTEGER, + "UUID" VARCHAR(50), + "PROJECT_UUID" VARCHAR(50), + "MODULE_UUID" VARCHAR(50), + "MODULE_UUID_PATH" VARCHAR(4000), + "NAME" VARCHAR(2000), + "DESCRIPTION" VARCHAR(2000), + "ENABLED" BOOLEAN NOT NULL DEFAULT TRUE, + "SCOPE" VARCHAR(3), + "QUALIFIER" VARCHAR(10), + "DEPRECATED_KEE" VARCHAR(400), + "PATH" VARCHAR(2000), + "LANGUAGE" VARCHAR(20), + "COPY_RESOURCE_ID" INTEGER, + "LONG_NAME" VARCHAR(2000), + "PERSON_ID" INTEGER, + "CREATED_AT" TIMESTAMP, + "AUTHORIZATION_UPDATED_AT" BIGINT +); -- 2.39.5