]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-7738 update table PROJECTS to have self UUIDs insteaf of ID
authorSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Fri, 10 Jun 2016 15:19:48 +0000 (17:19 +0200)
committerSébastien Lesaint <sebastien.lesaint@sonarsource.com>
Thu, 16 Jun 2016 11:49:19 +0000 (13:49 +0200)
26 files changed:
server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1220_add_uuid_columns_to_projects.rb [new file with mode: 0644]
server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1221_populate_uuid_columns_of_projects.rb [new file with mode: 0644]
server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1222_clean_orphan_rows_in_projects.rb [new file with mode: 0644]
server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1223_drop_index_projects_uuid_from_projects.rb [new file with mode: 0644]
server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1224_make_uuid_columns_not_null_on_projects.rb [new file with mode: 0644]
server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1225_recreate_index_projects_uuid_from_projects.rb [new file with mode: 0644]
server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1226_drop_index_projects_root_id_from_projects.rb [new file with mode: 0644]
server/sonar-web/src/main/webapp/WEB-INF/db/migrate/1227_drop_id_columns_from_projects.rb [new file with mode: 0644]
sonar-db/src/main/java/org/sonar/db/version/DatabaseVersion.java
sonar-db/src/main/java/org/sonar/db/version/MigrationStepModule.java
sonar-db/src/main/java/org/sonar/db/version/v60/AddUuidColumnsToProjects.java [new file with mode: 0644]
sonar-db/src/main/java/org/sonar/db/version/v60/CleanOrphanRowsInProjects.java [new file with mode: 0644]
sonar-db/src/main/java/org/sonar/db/version/v60/DropIdColumnsFromProjects.java [new file with mode: 0644]
sonar-db/src/main/java/org/sonar/db/version/v60/MakeUuidColumnsNotNullOnProjects.java [new file with mode: 0644]
sonar-db/src/main/java/org/sonar/db/version/v60/PopulateUuidColumnsOfProjects.java [new file with mode: 0644]
sonar-db/src/main/resources/org/sonar/db/version/rows-h2.sql
sonar-db/src/main/resources/org/sonar/db/version/schema-h2.ddl
sonar-db/src/test/java/org/sonar/db/version/MigrationStepModuleTest.java
sonar-db/src/test/java/org/sonar/db/version/v60/AddUuidColumnsToProjectsTest.java [new file with mode: 0644]
sonar-db/src/test/java/org/sonar/db/version/v60/DropIdColumnsFromProjectsTest.java [new file with mode: 0644]
sonar-db/src/test/java/org/sonar/db/version/v60/MakeUuidColumnsNotNullOnProjectsTest.java [new file with mode: 0644]
sonar-db/src/test/java/org/sonar/db/version/v60/PopulateUuidColumnsOfProjectsTest.java [new file with mode: 0644]
sonar-db/src/test/java/org/sonar/db/version/v60/PopulateUuidColumnsOfSnapshotsTest.java
sonar-db/src/test/resources/org/sonar/db/version/v60/AddUuidColumnsToProjectsTest/old_projects.sql [new file with mode: 0644]
sonar-db/src/test/resources/org/sonar/db/version/v60/MakeUuidColumnsNotNullOnProjectsTest/in_progress_projects.sql [new file with mode: 0644]
sonar-db/src/test/resources/org/sonar/db/version/v60/PopulateUuidColumnsOfProjectsTest/in_progress_projects.sql [new file with mode: 0644]

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 (file)
index 0000000..95fa983
--- /dev/null
@@ -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 (file)
index 0000000..b670911
--- /dev/null
@@ -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 (file)
index 0000000..0f06310
--- /dev/null
@@ -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 (file)
index 0000000..6305a0d
--- /dev/null
@@ -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 (file)
index 0000000..2db8db3
--- /dev/null
@@ -0,0 +1,31 @@
+#
+# SonarQube, open source software quality management tool.
+# Copyright (C) 2008-2014 SonarSource
+# mailto:contact AT sonarsource DOT com
+#
+# SonarQube is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 3 of the License, or (at your option) any later version.
+#
+# SonarQube is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#
+
+#
+# SonarQube 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 (file)
index 0000000..f9f6fba
--- /dev/null
@@ -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 (file)
index 0000000..bb859a8
--- /dev/null
@@ -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 (file)
index 0000000..6266cda
--- /dev/null
@@ -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
index a06eedfe409b48b82b23d038e735dcb4cd11d1de..887c87f8cfc53458055b7b14240e98f88f0a5d64 100644 (file)
@@ -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
index 7da3b5de2bc6e2139c3bad36584f5e2b677d1419..07a5e5d79f73d3d67f097c2174bb5328dc32effb 100644 (file)
@@ -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 (file)
index 0000000..9ebe7c5
--- /dev/null
@@ -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 (file)
index 0000000..2e19d2e
--- /dev/null
@@ -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 (file)
index 0000000..9b51cda
--- /dev/null
@@ -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 (file)
index 0000000..18152b3
--- /dev/null
@@ -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 (file)
index 0000000..f0c8c9d
--- /dev/null
@@ -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<Long, String> componentUuidById = buildComponentUuidMap(context);
+    if (componentUuidById.isEmpty()) {
+      return;
+    }
+
+    populateRootUuidColumnForRoots(context);
+    populateRootUuidColumnForSubnodes(context, componentUuidById);
+    populateCopyComponentUuidColumn(context, componentUuidById);
+    populatePersonUuidColumn(context, componentUuidById);
+  }
+
+  private static Map<Long, String> buildComponentUuidMap(Context context) throws SQLException {
+    Map<Long, String> 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<Long, String> 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<Long, String> 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<Long, String> 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<Long, String> 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<Long, String> 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<Long, String> 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;
+  }
+
+}
index df118b721214e08088702031eef492dd81fc8fba..ef60eb5d94ead3a537089e30ea6d8c62a13a6b59 100644 (file)
@@ -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;
index 299da2925386de051523c29b6d16a4b0ecf4019a..4861e6c87aaf406bd6ab1c95c9032bac7d8cae5a 100644 (file)
@@ -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");
 
index bd9c70e14a6c1843b47838479552e7afdcda5fe9..01cfda06075454dbf72035a4a9bf015d5b12e0a0 100644 (file)
@@ -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 (file)
index 0000000..6d8117e
--- /dev/null
@@ -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 (file)
index 0000000..0394308
--- /dev/null
@@ -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 (file)
index 0000000..a232ff2
--- /dev/null
@@ -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 (file)
index 0000000..a883b04
--- /dev/null
@@ -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<Map<String, Object>> 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<String, Object> 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);
+  }
+
+}
index 141ce50cd398309210688342bad9be2a0f1342d8..11dabd59e45177f3ddf26ecf5b7160f8c07b7e44 100644 (file)
@@ -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 (file)
index 0000000..d833144
--- /dev/null
@@ -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 (file)
index 0000000..5ea7d16
--- /dev/null
@@ -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 (file)
index 0000000..5ea7d16
--- /dev/null
@@ -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)
+);