--- /dev/null
+#
+# 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
--- /dev/null
+#
+# 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
--- /dev/null
+#
+# 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
--- /dev/null
+
+#
+# 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
--- /dev/null
+#
+# 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
--- /dev/null
+
+#
+# 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
--- /dev/null
+#
+# 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
--- /dev/null
+#
+# 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
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
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;
DeleteOrphanMeasuresWithoutComponent.class,
MakeComponentUuidNotNullOnMeasures.class,
DropProjectIdColumnFromMeasures.class,
- DropRememberMeColumnsFromUsers.class);
+ DropRememberMeColumnsFromUsers.class,
+ AddUuidColumnsToProjects.class,
+ PopulateUuidColumnsOfProjects.class,
+ CleanOrphanRowsInProjects.class,
+ MakeUuidColumnsNotNullOnProjects.class,
+ DropIdColumnsFromProjects.class);
}
}
--- /dev/null
+/*
+ * 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());
+ }
+
+}
--- /dev/null
+/*
+ * 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;
+ });
+ }
+
+}
--- /dev/null
+/*
+ * 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());
+ }
+
+}
--- /dev/null
+/*
+ * 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());
+ }
+
+}
--- /dev/null
+/*
+ * 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;
+ }
+
+}
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;
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),
"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
);
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");
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);
}
}
--- /dev/null
+/*
+ * 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);
+ }
+
+
+
+}
--- /dev/null
+/*
+ * 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");
+ }
+
+
+}
--- /dev/null
+/*
+ * 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;
+ }
+
+}
--- /dev/null
+/*
+ * 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);
+ }
+
+}
assertThat(row.get("ROOT_COMPONENT_UUID")).isEqualTo(rootComponentUuid);
}
-
}
--- /dev/null
+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
+);
--- /dev/null
+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)
+);
--- /dev/null
+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)
+);