From 4b7dc3b9c7e922dc494bc1e985cee0d277883e64 Mon Sep 17 00:00:00 2001 From: =?utf8?q?S=C3=A9bastien=20Lesaint?= Date: Fri, 10 Jun 2016 17:19:48 +0200 Subject: [PATCH] SONAR-7738 update table PROJECTS to have self UUIDs insteaf of ID --- .../1220_add_uuid_columns_to_projects.rb | 29 +++ .../1221_populate_uuid_columns_of_projects.rb | 29 +++ .../1222_clean_orphan_rows_in_projects.rb | 29 +++ ..._drop_index_projects_uuid_from_projects.rb | 34 ++++ ..._make_uuid_columns_not_null_on_projects.rb | 31 ++++ ...reate_index_projects_uuid_from_projects.rb | 30 ++++ ...op_index_projects_root_id_from_projects.rb | 29 +++ .../1227_drop_id_columns_from_projects.rb | 29 +++ .../org/sonar/db/version/DatabaseVersion.java | 2 +- .../sonar/db/version/MigrationStepModule.java | 16 +- .../version/v60/AddUuidColumnsToProjects.java | 47 +++++ .../v60/CleanOrphanRowsInProjects.java | 48 +++++ .../v60/DropIdColumnsFromProjects.java | 44 +++++ .../v60/MakeUuidColumnsNotNullOnProjects.java | 46 +++++ .../v60/PopulateUuidColumnsOfProjects.java | 167 ++++++++++++++++++ .../org/sonar/db/version/rows-h2.sql | 8 + .../org/sonar/db/version/schema-h2.ddl | 10 +- .../db/version/MigrationStepModuleTest.java | 2 +- .../v60/AddUuidColumnsToProjectsTest.java | 70 ++++++++ .../v60/DropIdColumnsFromProjectsTest.java | 49 +++++ .../MakeUuidColumnsNotNullOnProjectsTest.java | 96 ++++++++++ .../PopulateUuidColumnsOfProjectsTest.java | 116 ++++++++++++ .../PopulateUuidColumnsOfSnapshotsTest.java | 1 - .../old_projects.sql | 22 +++ .../in_progress_projects.sql | 25 +++ .../in_progress_projects.sql | 25 +++ 26 files changed, 1023 insertions(+), 11 deletions(-) create mode 100644 server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1220_add_uuid_columns_to_projects.rb create mode 100644 server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1221_populate_uuid_columns_of_projects.rb create mode 100644 server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1222_clean_orphan_rows_in_projects.rb create mode 100644 server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1223_drop_index_projects_uuid_from_projects.rb create mode 100644 server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1224_make_uuid_columns_not_null_on_projects.rb create mode 100644 server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1225_recreate_index_projects_uuid_from_projects.rb create mode 100644 server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1226_drop_index_projects_root_id_from_projects.rb create mode 100644 server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1227_drop_id_columns_from_projects.rb create mode 100644 sonar-db/src/main/java/org/sonar/db/version/v60/AddUuidColumnsToProjects.java create mode 100644 sonar-db/src/main/java/org/sonar/db/version/v60/CleanOrphanRowsInProjects.java create mode 100644 sonar-db/src/main/java/org/sonar/db/version/v60/DropIdColumnsFromProjects.java create mode 100644 sonar-db/src/main/java/org/sonar/db/version/v60/MakeUuidColumnsNotNullOnProjects.java create mode 100644 sonar-db/src/main/java/org/sonar/db/version/v60/PopulateUuidColumnsOfProjects.java create mode 100644 sonar-db/src/test/java/org/sonar/db/version/v60/AddUuidColumnsToProjectsTest.java create mode 100644 sonar-db/src/test/java/org/sonar/db/version/v60/DropIdColumnsFromProjectsTest.java create mode 100644 sonar-db/src/test/java/org/sonar/db/version/v60/MakeUuidColumnsNotNullOnProjectsTest.java create mode 100644 sonar-db/src/test/java/org/sonar/db/version/v60/PopulateUuidColumnsOfProjectsTest.java create mode 100644 sonar-db/src/test/resources/org/sonar/db/version/v60/AddUuidColumnsToProjectsTest/old_projects.sql create mode 100644 sonar-db/src/test/resources/org/sonar/db/version/v60/MakeUuidColumnsNotNullOnProjectsTest/in_progress_projects.sql create mode 100644 sonar-db/src/test/resources/org/sonar/db/version/v60/PopulateUuidColumnsOfProjectsTest/in_progress_projects.sql diff --git a/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1220_add_uuid_columns_to_projects.rb b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1220_add_uuid_columns_to_projects.rb new file mode 100644 index 00000000000..95fa9837b59 --- /dev/null +++ b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1220_add_uuid_columns_to_projects.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 AddUuidColumnsToProjects < ActiveRecord::Migration + + def self.up + execute_java_migration('org.sonar.db.version.v60.AddUuidColumnsToProjects') + end +end diff --git a/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1221_populate_uuid_columns_of_projects.rb b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1221_populate_uuid_columns_of_projects.rb new file mode 100644 index 00000000000..b67091182d3 --- /dev/null +++ b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1221_populate_uuid_columns_of_projects.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 PopulateUuidColumnsOfProjects < ActiveRecord::Migration + + def self.up + execute_java_migration('org.sonar.db.version.v60.PopulateUuidColumnsOfProjects') + end +end diff --git a/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1222_clean_orphan_rows_in_projects.rb b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1222_clean_orphan_rows_in_projects.rb new file mode 100644 index 00000000000..0f063102b03 --- /dev/null +++ b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1222_clean_orphan_rows_in_projects.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 CleanOrphanRowsInProjects < ActiveRecord::Migration + + def self.up + execute_java_migration('org.sonar.db.version.v60.CleanOrphanRowsInProjects') + end +end diff --git a/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1223_drop_index_projects_uuid_from_projects.rb b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1223_drop_index_projects_uuid_from_projects.rb new file mode 100644 index 00000000000..6305a0d80d6 --- /dev/null +++ b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1223_drop_index_projects_uuid_from_projects.rb @@ -0,0 +1,34 @@ + +# +# 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 DropIndexProjectsUuidFromProjects < ActiveRecord::Migration + + def self.up + begin + remove_index :projects, :name => 'projects_uuid' + rescue + #ignore + end + end +end diff --git a/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1224_make_uuid_columns_not_null_on_projects.rb b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1224_make_uuid_columns_not_null_on_projects.rb new file mode 100644 index 00000000000..2db8db3f4ba --- /dev/null +++ b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1224_make_uuid_columns_not_null_on_projects.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 MakeUuidColumnsNotNullOnProjects < ActiveRecord::Migration + + def self.up + execute_java_migration('org.sonar.db.version.v60.MakeUuidColumnsNotNullOnProjects') + + add_index :projects, :root_uuid, :name => 'projects_root_uuid' + end +end diff --git a/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1225_recreate_index_projects_uuid_from_projects.rb b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1225_recreate_index_projects_uuid_from_projects.rb new file mode 100644 index 00000000000..f9f6fbad51c --- /dev/null +++ b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1225_recreate_index_projects_uuid_from_projects.rb @@ -0,0 +1,30 @@ + +# +# 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 RecreateIndexProjectsUuidFromProjects < ActiveRecord::Migration + + def self.up + add_index :projects, :uuid, :name => 'projects_uuid' + end +end diff --git a/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1226_drop_index_projects_root_id_from_projects.rb b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1226_drop_index_projects_root_id_from_projects.rb new file mode 100644 index 00000000000..bb859a82616 --- /dev/null +++ b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1226_drop_index_projects_root_id_from_projects.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 DropIndexProjectsRootIdFromProjects < ActiveRecord::Migration + + def self.up + remove_index :projects, :name => 'projects_root_id' + end +end diff --git a/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1227_drop_id_columns_from_projects.rb b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1227_drop_id_columns_from_projects.rb new file mode 100644 index 00000000000..6266cdad3fa --- /dev/null +++ b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1227_drop_id_columns_from_projects.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 DropIdColumnsFromProjects < ActiveRecord::Migration + + def self.up + execute_java_migration('org.sonar.db.version.v60.DropIdColumnsFromProjects') + 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 a06eedfe409..887c87f8cfc 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_219; + public static final int LAST_VERSION = 1_227; /** * 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 7da3b5de2bc..07a5e5d79f7 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 @@ -84,20 +84,25 @@ 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.AddComponentUuidColumnToMeasures; +import org.sonar.db.version.v60.AddUuidColumnsToProjects; import org.sonar.db.version.v60.AddUuidColumnsToResourceIndex; import org.sonar.db.version.v60.AddUuidColumnsToSnapshots; +import org.sonar.db.version.v60.CleanOrphanRowsInProjects; import org.sonar.db.version.v60.CleanOrphanRowsInResourceIndex; import org.sonar.db.version.v60.CleanOrphanRowsInSnapshots; import org.sonar.db.version.v60.DeleteOrphanMeasuresWithoutComponent; +import org.sonar.db.version.v60.DropIdColumnsFromProjects; import org.sonar.db.version.v60.DropIdColumnsFromResourceIndex; -import org.sonar.db.version.v60.DropRememberMeColumnsFromUsers; -import org.sonar.db.version.v60.DropUnusedMeasuresColumns; import org.sonar.db.version.v60.DropIdColumnsFromSnapshots; import org.sonar.db.version.v60.DropProjectIdColumnFromMeasures; +import org.sonar.db.version.v60.DropRememberMeColumnsFromUsers; +import org.sonar.db.version.v60.DropUnusedMeasuresColumns; import org.sonar.db.version.v60.MakeComponentUuidNotNullOnMeasures; +import org.sonar.db.version.v60.MakeUuidColumnsNotNullOnProjects; import org.sonar.db.version.v60.MakeUuidColumnsNotNullOnResourceIndex; import org.sonar.db.version.v60.MakeUuidColumnsNotNullOnSnapshots; import org.sonar.db.version.v60.PopulateComponentUuidOfMeasures; +import org.sonar.db.version.v60.PopulateUuidColumnsOfProjects; import org.sonar.db.version.v60.PopulateUuidColumnsOfResourceIndex; import org.sonar.db.version.v60.PopulateUuidColumnsOfSnapshots; @@ -201,6 +206,11 @@ public class MigrationStepModule extends Module { DeleteOrphanMeasuresWithoutComponent.class, MakeComponentUuidNotNullOnMeasures.class, DropProjectIdColumnFromMeasures.class, - DropRememberMeColumnsFromUsers.class); + DropRememberMeColumnsFromUsers.class, + AddUuidColumnsToProjects.class, + PopulateUuidColumnsOfProjects.class, + CleanOrphanRowsInProjects.class, + MakeUuidColumnsNotNullOnProjects.class, + DropIdColumnsFromProjects.class); } } diff --git a/sonar-db/src/main/java/org/sonar/db/version/v60/AddUuidColumnsToProjects.java b/sonar-db/src/main/java/org/sonar/db/version/v60/AddUuidColumnsToProjects.java new file mode 100644 index 00000000000..9ebe7c5f5f2 --- /dev/null +++ b/sonar-db/src/main/java/org/sonar/db/version/v60/AddUuidColumnsToProjects.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.AddColumnsBuilder; +import org.sonar.db.version.DdlChange; + +import static org.sonar.db.version.VarcharColumnDef.newVarcharColumnDefBuilder; + +public class AddUuidColumnsToProjects extends DdlChange { + + private static final String TABLE_PROJECTS = "projects"; + private static final int UUID_VARCHAR_SIZE = 50; + + public AddUuidColumnsToProjects(Database db) { + super(db); + } + + @Override + public void execute(Context context) throws SQLException { + context.execute(new AddColumnsBuilder(getDialect(), TABLE_PROJECTS) + .addColumn(newVarcharColumnDefBuilder().setColumnName("root_uuid").setLimit(UUID_VARCHAR_SIZE).setIsNullable(true).build()) + .addColumn(newVarcharColumnDefBuilder().setColumnName("copy_component_uuid").setLimit(UUID_VARCHAR_SIZE).setIsNullable(true).build()) + .addColumn(newVarcharColumnDefBuilder().setColumnName("developer_uuid").setLimit(UUID_VARCHAR_SIZE).setIsNullable(true).build()) + .build()); + } + +} diff --git a/sonar-db/src/main/java/org/sonar/db/version/v60/CleanOrphanRowsInProjects.java b/sonar-db/src/main/java/org/sonar/db/version/v60/CleanOrphanRowsInProjects.java new file mode 100644 index 00000000000..2e19d2e7a78 --- /dev/null +++ b/sonar-db/src/main/java/org/sonar/db/version/v60/CleanOrphanRowsInProjects.java @@ -0,0 +1,48 @@ +/* + * 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 CleanOrphanRowsInProjects extends BaseDataChange { + + public CleanOrphanRowsInProjects(Database db) { + super(db); + } + + @Override + public void execute(Context context) throws SQLException { + MassUpdate massUpdate = context.prepareMassUpdate(); + massUpdate.select("SELECT p.id from projects p where p.root_uuid is null" + + " or (p.copy_resource_id is not null and p.copy_component_uuid is null)" + + " or (p.person_id is not null and p.developer_uuid is null)"); + massUpdate.update("DELETE from projects WHERE id=?"); + massUpdate.rowPluralName("orphan projects"); + massUpdate.execute((row, update) -> { + long projectId = row.getLong(1); + update.setLong(1, projectId); + return true; + }); + } + +} diff --git a/sonar-db/src/main/java/org/sonar/db/version/v60/DropIdColumnsFromProjects.java b/sonar-db/src/main/java/org/sonar/db/version/v60/DropIdColumnsFromProjects.java new file mode 100644 index 00000000000..9b51cda9ded --- /dev/null +++ b/sonar-db/src/main/java/org/sonar/db/version/v60/DropIdColumnsFromProjects.java @@ -0,0 +1,44 @@ +/* + * 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 DropIdColumnsFromProjects extends DdlChange { + + private static final String TABLE_PROJECTS = "projects"; + + public DropIdColumnsFromProjects(Database db) { + super(db); + } + + @Override + public void execute(Context context) throws SQLException { + context.execute( + new DropColumnsBuilder( + getDialect(), TABLE_PROJECTS, + "root_id", "copy_resource_id", "person_id") + .build()); + } + +} diff --git a/sonar-db/src/main/java/org/sonar/db/version/v60/MakeUuidColumnsNotNullOnProjects.java b/sonar-db/src/main/java/org/sonar/db/version/v60/MakeUuidColumnsNotNullOnProjects.java new file mode 100644 index 00000000000..18152b30c26 --- /dev/null +++ b/sonar-db/src/main/java/org/sonar/db/version/v60/MakeUuidColumnsNotNullOnProjects.java @@ -0,0 +1,46 @@ +/* + * 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.AlterColumnsBuilder; +import org.sonar.db.version.DdlChange; + +import static org.sonar.db.version.VarcharColumnDef.newVarcharColumnDefBuilder; + +public class MakeUuidColumnsNotNullOnProjects extends DdlChange { + + private static final String TABLE_PROJECTS = "projects"; + private static final int UUID_VARCHAR_SIZE = 50; + + public MakeUuidColumnsNotNullOnProjects(Database db) { + super(db); + } + + @Override + public void execute(Context context) throws SQLException { + context.execute(new AlterColumnsBuilder(getDialect(), TABLE_PROJECTS) + .updateColumn(newVarcharColumnDefBuilder().setColumnName("uuid").setLimit(UUID_VARCHAR_SIZE).setIsNullable(false).build()) + .updateColumn(newVarcharColumnDefBuilder().setColumnName("root_uuid").setLimit(UUID_VARCHAR_SIZE).setIsNullable(false).build()) + .build()); + } + +} diff --git a/sonar-db/src/main/java/org/sonar/db/version/v60/PopulateUuidColumnsOfProjects.java b/sonar-db/src/main/java/org/sonar/db/version/v60/PopulateUuidColumnsOfProjects.java new file mode 100644 index 00000000000..f0c8c9dcf68 --- /dev/null +++ b/sonar-db/src/main/java/org/sonar/db/version/v60/PopulateUuidColumnsOfProjects.java @@ -0,0 +1,167 @@ +/* + * 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.api.utils.log.Logger; +import org.sonar.api.utils.log.Loggers; +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 PopulateUuidColumnsOfProjects extends BaseDataChange { + private static final Logger LOG = Loggers.get(PopulateUuidColumnsOfProjects.class); + + public PopulateUuidColumnsOfProjects(Database db) { + super(db); + } + + @Override + public void execute(Context context) throws SQLException { + + Map componentUuidById = buildComponentUuidMap(context); + if (componentUuidById.isEmpty()) { + return; + } + + populateRootUuidColumnForRoots(context); + populateRootUuidColumnForSubnodes(context, componentUuidById); + populateCopyComponentUuidColumn(context, componentUuidById); + populatePersonUuidColumn(context, componentUuidById); + } + + private static Map buildComponentUuidMap(Context context) throws SQLException { + Map componentUuidById = new HashMap<>(); + // rootId for root nodes (ie. column root_id is null) + context.prepareSelect("select distinct p1.id, p1.uuid from projects p1" + + " where p1.root_id is null and p1.root_uuid is null") + .scroll(row -> componentUuidById.put(row.getLong(1), row.getString(2))); + // rootId for other nodes (ie. column root_id is not null) + context.prepareSelect("select distinct p1.id, p1.uuid from projects p1" + + " join projects p2 on p1.id = p2.root_id" + + " where p2.root_uuid is null") + .scroll(row -> componentUuidById.put(row.getLong(1), row.getString(2))); + // copyResourceId + context.prepareSelect("select distinct p1.id, p1.uuid from projects p1" + + " join projects p2 on p1.id = p2.copy_resource_id" + + " where p2.copy_resource_id is not null and p2.copy_component_uuid is null") + .scroll(row -> componentUuidById.put(row.getLong(1), row.getString(2))); + // person_id + context.prepareSelect("select distinct p1.id, p1.uuid from projects p1" + + " join projects p2 on p1.id = p2.person_id" + + " where p2.person_id is not null and p2.developer_uuid is null") + .scroll(row -> componentUuidById.put(row.getLong(1), row.getString(2))); + return componentUuidById; + } + + private static void populateRootUuidColumnForRoots(Context context) throws SQLException { + MassUpdate massUpdate = context.prepareMassUpdate(); + massUpdate.select("SELECT distinct p.id from projects p where p.root_id is null and p.root_uuid is null"); + massUpdate.update("UPDATE projects SET root_uuid=uuid WHERE id=? and root_id is null and root_uuid is null"); + massUpdate.rowPluralName("root uuid of root components"); + massUpdate.execute(PopulateUuidColumnsOfProjects::handleRootIdUpdateForRootNodes); + } + + private static boolean handleRootIdUpdateForRootNodes(Select.Row row, SqlStatement update) throws SQLException { + long rootId = row.getLong(1); + + update.setLong(1, rootId); + + return true; + } + + private static void populateRootUuidColumnForSubnodes(Context context, Map componentUuidById) throws SQLException { + // update all rows with specific root_id which have no root_uuid yet in a single update + // this will be efficient as root_id is indexed + MassUpdate massUpdate = context.prepareMassUpdate(); + massUpdate.select("SELECT distinct p.root_id from projects p where p.root_id is not null and p.root_uuid is null"); + massUpdate.update("UPDATE projects SET root_uuid=? WHERE root_id=? and root_uuid is null"); + massUpdate.rowPluralName("root uuid of non-root components"); + massUpdate.execute((row, update) -> handleRootIdUpdateForSubNodes(componentUuidById, row, update)); + } + + private static boolean handleRootIdUpdateForSubNodes(Map componentUuidById, Select.Row row, SqlStatement update) throws SQLException { + long rootId = row.getLong(1); + String rootUuid = componentUuidById.get(rootId); + + if (rootUuid == null) { + LOG.trace("No UUID found for rootId={}", rootUuid); + return false; + } + + update.setString(1, rootUuid); + update.setLong(2, rootId); + + return true; + } + + private static void populateCopyComponentUuidColumn(Context context, Map componentUuidById) throws SQLException { + MassUpdate massUpdate = context.prepareMassUpdate(); + massUpdate.select("SELECT p.id, p.copy_resource_id from projects p where p.copy_resource_id is not null and p.copy_component_uuid is null"); + massUpdate.update("UPDATE projects SET copy_component_uuid=? WHERE id=?"); + massUpdate.rowPluralName("copy component uuid of components"); + massUpdate.execute((row, update) -> handleCopyComponentUuidUpdate(componentUuidById, row, update)); + } + + private static boolean handleCopyComponentUuidUpdate(Map componentUuidById, Select.Row row, SqlStatement update) throws SQLException { + long id = row.getLong(1); + long copyResourceId = row.getLong(2); + + String copyComponentUuid = componentUuidById.get(copyResourceId); + if (copyComponentUuid == null) { + LOG.trace("No UUID found for copyResourceId={}", copyResourceId); + return false; + } + + update.setString(1, copyComponentUuid); + update.setLong(2, id); + + return true; + } + + private static void populatePersonUuidColumn(Context context, Map componentUuidById) throws SQLException { + MassUpdate massUpdate = context.prepareMassUpdate(); + massUpdate.select("SELECT p.id, p.person_id from projects p where p.person_id is not null and p.developer_uuid is null"); + massUpdate.update("UPDATE projects SET developer_uuid=? WHERE id=?"); + massUpdate.rowPluralName("person uuid of components"); + massUpdate.execute((row, update) -> handleDeveloperUuuidUpdate(componentUuidById, row, update)); + } + + private static boolean handleDeveloperUuuidUpdate(Map componentUuidById, Select.Row row, SqlStatement update) throws SQLException { + long id = row.getLong(1); + long personId = row.getLong(2); + + String developerUuid = componentUuidById.get(personId); + if (developerUuid == null) { + LOG.trace("No UUID found for personId={}", personId); + return false; + } + + update.setString(1, developerUuid); + update.setLong(2, id); + + return true; + } + +} 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 df118b72121..ef60eb5d94e 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 @@ -426,6 +426,14 @@ INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1216'); INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1217'); INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1218'); INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1219'); +INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1220'); +INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1221'); +INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1222'); +INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1223'); +INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1224'); +INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1225'); +INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1226'); +INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('1227'); INSERT INTO USERS(ID, LOGIN, NAME, EMAIL, EXTERNAL_IDENTITY, EXTERNAL_IDENTITY_PROVIDER, USER_LOCAL, CRYPTED_PASSWORD, SALT, CREATED_AT, UPDATED_AT) VALUES (1, 'admin', 'Administrator', '', 'admin', 'sonarqube', true, 'a373a0e667abb2604c1fd571eb4ad47fe8cc0878', '48bc4b0d93179b5103fd3885ea9119498e9d161b', '1418215735482', '1418215735482'); ALTER TABLE USERS ALTER COLUMN ID RESTART WITH 2; 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 299da292538..4861e6c87aa 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 @@ -214,8 +214,8 @@ CREATE TABLE "PROJECT_MEASURES" ( 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), + "UUID" VARCHAR(50) NOT NULL, + "ROOT_UUID" VARCHAR(50) NOT NULL, "PROJECT_UUID" VARCHAR(50), "MODULE_UUID" VARCHAR(50), "MODULE_UUID_PATH" VARCHAR(4000), @@ -227,9 +227,9 @@ CREATE TABLE "PROJECTS" ( "DEPRECATED_KEE" VARCHAR(400), "PATH" VARCHAR(2000), "LANGUAGE" VARCHAR(20), - "COPY_RESOURCE_ID" INTEGER, + "COPY_COMPONENT_UUID" VARCHAR(50), "LONG_NAME" VARCHAR(2000), - "PERSON_ID" INTEGER, + "DEVELOPER_UUID" VARCHAR(50), "CREATED_AT" TIMESTAMP, "AUTHORIZATION_UPDATED_AT" BIGINT ); @@ -593,7 +593,7 @@ CREATE INDEX "MANUAL_MEASURES_COMPONENT_UUID" ON "MANUAL_MEASURES" ("COMPONENT_U CREATE UNIQUE INDEX "PROJECTS_KEE" ON "PROJECTS" ("KEE"); -CREATE INDEX "PROJECTS_ROOT_ID" ON "PROJECTS" ("ROOT_ID"); +CREATE INDEX "PROJECTS_ROOT_UUID" ON "PROJECTS" ("ROOT_UUID"); CREATE UNIQUE INDEX "PROJECTS_UUID" ON "PROJECTS" ("UUID"); 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 bd9c70e14a6..01cfda06075 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(82); + assertThat(container.size()).isEqualTo(87); } } diff --git a/sonar-db/src/test/java/org/sonar/db/version/v60/AddUuidColumnsToProjectsTest.java b/sonar-db/src/test/java/org/sonar/db/version/v60/AddUuidColumnsToProjectsTest.java new file mode 100644 index 00000000000..6d8117e91d5 --- /dev/null +++ b/sonar-db/src/test/java/org/sonar/db/version/v60/AddUuidColumnsToProjectsTest.java @@ -0,0 +1,70 @@ +/* + * 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; + +public class AddUuidColumnsToProjectsTest { + + public static final String PROJECTS_TABLE = "projects"; + @Rule + public DbTester db = DbTester.createForSchema(System2.INSTANCE, AddUuidColumnsToProjectsTest.class, "old_projects.sql"); + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + private AddUuidColumnsToProjects underTest = new AddUuidColumnsToProjects(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( + PROJECTS_TABLE, + "KEE", "key_" + i, + "ENABLED", "true"); + } + db.commit(); + + underTest.execute(); + + verifyAddedColumns(); + } + + private void verifyAddedColumns() { + db.assertColumnDefinition(PROJECTS_TABLE, "root_uuid", Types.VARCHAR, 50, true); + db.assertColumnDefinition(PROJECTS_TABLE, "copy_component_uuid", Types.VARCHAR, 50, true); + db.assertColumnDefinition(PROJECTS_TABLE, "developer_uuid", Types.VARCHAR, 50, true); + } + + + +} diff --git a/sonar-db/src/test/java/org/sonar/db/version/v60/DropIdColumnsFromProjectsTest.java b/sonar-db/src/test/java/org/sonar/db/version/v60/DropIdColumnsFromProjectsTest.java new file mode 100644 index 00000000000..03943089424 --- /dev/null +++ b/sonar-db/src/test/java/org/sonar/db/version/v60/DropIdColumnsFromProjectsTest.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.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 DropIdColumnsFromProjectsTest { + + private Database database = mock(Database.class); + + private DropIdColumnsFromProjects underTest = new DropIdColumnsFromProjects(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 projects DROP COLUMN root_id, DROP COLUMN copy_resource_id, DROP COLUMN person_id"); + } + + +} diff --git a/sonar-db/src/test/java/org/sonar/db/version/v60/MakeUuidColumnsNotNullOnProjectsTest.java b/sonar-db/src/test/java/org/sonar/db/version/v60/MakeUuidColumnsNotNullOnProjectsTest.java new file mode 100644 index 00000000000..a232ff295b4 --- /dev/null +++ b/sonar-db/src/test/java/org/sonar/db/version/v60/MakeUuidColumnsNotNullOnProjectsTest.java @@ -0,0 +1,96 @@ +/* + * 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 MakeUuidColumnsNotNullOnProjectsTest { + + private static final String PROJECTS_TABLE = "projects"; + + @Rule + public DbTester db = DbTester.createForSchema(System2.INSTANCE, MakeUuidColumnsNotNullOnProjectsTest.class, + "in_progress_projects.sql"); + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + private MakeUuidColumnsNotNullOnProjects underTest = new MakeUuidColumnsNotNullOnProjects(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 { + insertComponent(1, true, true); + insertComponent(2, true, true); + + underTest.execute(); + + verifyColumnDefinitions(); + } + + @Test + public void migration_fails_if_some_row_has_a_null_uuid() throws SQLException { + insertComponent(1, false, true); + + expectedException.expect(IllegalStateException.class); + expectedException.expectMessage("Fail to execute"); + + underTest.execute(); + } + + @Test + public void migration_fails_if_some_row_has_a_null_rootuuid() throws SQLException { + insertComponent(1, true, false); + + expectedException.expect(IllegalStateException.class); + expectedException.expectMessage("Fail to execute"); + + underTest.execute(); + } + + private void verifyColumnDefinitions() { + db.assertColumnDefinition(PROJECTS_TABLE, "uuid", Types.VARCHAR, 50, false); + db.assertColumnDefinition(PROJECTS_TABLE, "root_uuid", Types.VARCHAR, 50, false); + } + + private String insertComponent(long id, boolean hasUuid, boolean hasRootUuid) { + String uuid = "uuid_" + id; + db.executeInsert( + "projects", + "ID", valueOf(id), + "UUID", hasUuid ? "uuid_" + id : null, + "ROOT_UUID", hasRootUuid ? "root_uuuid_" + id : null); + return uuid; + } + +} diff --git a/sonar-db/src/test/java/org/sonar/db/version/v60/PopulateUuidColumnsOfProjectsTest.java b/sonar-db/src/test/java/org/sonar/db/version/v60/PopulateUuidColumnsOfProjectsTest.java new file mode 100644 index 00000000000..a883b04c99f --- /dev/null +++ b/sonar-db/src/test/java/org/sonar/db/version/v60/PopulateUuidColumnsOfProjectsTest.java @@ -0,0 +1,116 @@ +/* + * 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 PopulateUuidColumnsOfProjectsTest { + + @Rule + public DbTester db = DbTester.createForSchema(System2.INSTANCE, PopulateUuidColumnsOfProjectsTest.class, + "in_progress_projects.sql"); + + private PopulateUuidColumnsOfProjects underTest = new PopulateUuidColumnsOfProjects(db.database()); + + @Test + public void migration_has_no_effect_on_empty_tables() throws SQLException { + underTest.execute(); + + 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(1, null, null, null); // project + insertComponent(2, 1L, null, null); // a module or something not a project + String uuid3 = insertComponent(3, null, null, null); // developer + insertComponent(4, 3L, 1L, 3L); // a project copy of project 1 for developer 3 + String uuid5 = insertComponent(5, null, null, null); // another project + String uuid6 = insertComponent(6, null, null, null); // a view + insertComponent(7, 6L, 5L, null); // a project view of project 5 + insertComponent(8, 200L, 1L, 200L); // a project copy of project 1 for developer 200 (does't exist) + insertComponent(9, 6L, 300L, null); // a project view of project 300 (doesn't exist) + insertComponent(10, 400L, null, null); // a module of a non existing project + db.commit(); + + underTest.execute(); + + verifyProject(1, null, uuid1, null, null, null, null); + verifyProject(2, 1L, uuid1, null, null, null, null); + verifyProject(3, null, uuid3, null, null, null, null); + verifyProject(4, 3L, uuid3, 1L, uuid1, 3L, uuid3); + verifyProject(5, null, uuid5, null, null, null, null); + verifyProject(6, null, uuid6, null, null, null, null); + verifyProject(7, 6L, uuid6, 5L, uuid5, null, null); + verifyProject(9, 6L, uuid6, 300L, null, null, null); + verifyProject(10, 400L, null, null, null, null, null); + } + + @Test + public void migration_is_reentrant() throws SQLException { + String uuid1 = insertComponent(1, null, null, null); // project + + underTest.execute(); + verifyProject(1, null, uuid1, null, null, null, null); + + underTest.execute(); + verifyProject(1, null, uuid1, null, null, null, null); + } + + private String insertComponent(long id, @Nullable Long rootId, @Nullable Long copyResourceId, @Nullable Long personId) { + String uuid = "uuid_" + id; + db.executeInsert( + "projects", + "ID", valueOf(id), + "UUID", uuid, + "ROOT_ID", toString(rootId), + "COPY_RESOURCE_ID", toString(copyResourceId), + "PERSON_ID", toString(personId)); + return uuid; + } + + private static String toString(@Nullable Long aLong) { + return aLong == null ? null : valueOf(aLong); + } + + private void verifyProject(long id, @Nullable Long rootId, @Nullable String rootUuid, @Nullable Long copyResourceId, @Nullable String copyComponentUuuid, @Nullable Long personId, + @Nullable String developerUuid) { + List> rows = db.select("select ROOT_ID, ROOT_UUID, COPY_RESOURCE_ID, COPY_COMPONENT_UUID, PERSON_ID, DEVELOPER_UUID from projects where ID=" + id); + assertThat(rows).hasSize(1); + Map row = rows.get(0); + assertThat(row.get("ROOT_ID")).isEqualTo(rootId); + assertThat(row.get("ROOT_UUID")).isEqualTo(rootUuid); + assertThat(row.get("COPY_RESOURCE_ID")).isEqualTo(copyResourceId); + assertThat(row.get("COPY_COMPONENT_UUID")).isEqualTo(copyComponentUuuid); + assertThat(row.get("PERSON_ID")).isEqualTo(personId); + assertThat(row.get("DEVELOPER_UUID")).isEqualTo(developerUuid); + } + +} diff --git a/sonar-db/src/test/java/org/sonar/db/version/v60/PopulateUuidColumnsOfSnapshotsTest.java b/sonar-db/src/test/java/org/sonar/db/version/v60/PopulateUuidColumnsOfSnapshotsTest.java index 141ce50cd39..11dabd59e45 100644 --- a/sonar-db/src/test/java/org/sonar/db/version/v60/PopulateUuidColumnsOfSnapshotsTest.java +++ b/sonar-db/src/test/java/org/sonar/db/version/v60/PopulateUuidColumnsOfSnapshotsTest.java @@ -118,5 +118,4 @@ public class PopulateUuidColumnsOfSnapshotsTest { assertThat(row.get("ROOT_COMPONENT_UUID")).isEqualTo(rootComponentUuid); } - } diff --git a/sonar-db/src/test/resources/org/sonar/db/version/v60/AddUuidColumnsToProjectsTest/old_projects.sql b/sonar-db/src/test/resources/org/sonar/db/version/v60/AddUuidColumnsToProjectsTest/old_projects.sql new file mode 100644 index 00000000000..d8331447c2f --- /dev/null +++ b/sonar-db/src/test/resources/org/sonar/db/version/v60/AddUuidColumnsToProjectsTest/old_projects.sql @@ -0,0 +1,22 @@ +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 +); diff --git a/sonar-db/src/test/resources/org/sonar/db/version/v60/MakeUuidColumnsNotNullOnProjectsTest/in_progress_projects.sql b/sonar-db/src/test/resources/org/sonar/db/version/v60/MakeUuidColumnsNotNullOnProjectsTest/in_progress_projects.sql new file mode 100644 index 00000000000..5ea7d165ad3 --- /dev/null +++ b/sonar-db/src/test/resources/org/sonar/db/version/v60/MakeUuidColumnsNotNullOnProjectsTest/in_progress_projects.sql @@ -0,0 +1,25 @@ +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, + "ROOT_UUID" VARCHAR(50), + "COPY_COMPONENT_UUID" VARCHAR(50), + "DEVELOPER_UUID" VARCHAR(50) +); diff --git a/sonar-db/src/test/resources/org/sonar/db/version/v60/PopulateUuidColumnsOfProjectsTest/in_progress_projects.sql b/sonar-db/src/test/resources/org/sonar/db/version/v60/PopulateUuidColumnsOfProjectsTest/in_progress_projects.sql new file mode 100644 index 00000000000..5ea7d165ad3 --- /dev/null +++ b/sonar-db/src/test/resources/org/sonar/db/version/v60/PopulateUuidColumnsOfProjectsTest/in_progress_projects.sql @@ -0,0 +1,25 @@ +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, + "ROOT_UUID" VARCHAR(50), + "COPY_COMPONENT_UUID" VARCHAR(50), + "DEVELOPER_UUID" VARCHAR(50) +); -- 2.39.5