org.sonar.db.version.v60.PopulateUuidPathColumnOnProjects Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of sonar-db Show documentation
Show all versions of sonar-db Show documentation
Create and request SonarQube schema
/*
* 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 com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
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;
import static java.util.stream.Collectors.toCollection;
public class PopulateUuidPathColumnOnProjects extends BaseDataChange {
private static final Logger LOG = Loggers.get(PopulateUuidPathColumnOnProjects.class);
private static final Joiner PATH_JOINER = Joiner.on('.');
private static final Splitter PATH_SPLITTER = Splitter.on('.').omitEmptyStrings();
private static final String PATH_SEPARATOR = ".";
private static final String ROOT_PATH = PATH_SEPARATOR;
public PopulateUuidPathColumnOnProjects(Database db) {
super(db);
}
@Override
public void execute(Context context) throws SQLException {
// group upgrades by tree of component
List rootComponentUuids = context
.prepareSelect("select distinct project_uuid from projects where uuid_path is null")
.list(row -> row.getString(1));
for (String rootUuid : rootComponentUuids) {
handleRoot(rootUuid, context);
}
handleOrphans(context);
}
private void handleRoot(String rootComponentUuid, Context context) throws SQLException {
Relations relations = new Relations();
context
.prepareSelect("select s.id, s.path, s.component_uuid from snapshots s where s.root_component_uuid=? and s.islast=?")
.setString(1, rootComponentUuid)
.setBoolean(2, true)
.scroll(row -> {
long snapshotId = row.getLong(1);
String snapshotPath = row.getString(2);
String componentUuid = row.getString(3);
relations.add(new Snapshot(snapshotId, snapshotPath, componentUuid));
});
MassUpdate massUpdate = context.prepareMassUpdate();
massUpdate.select("select p.uuid, p.project_uuid from projects p where p.project_uuid=? and p.uuid_path is null").setString(1, rootComponentUuid);
massUpdate.update("update projects set uuid_path=? where uuid=? and uuid_path is null");
massUpdate.rowPluralName("components in tree of " + rootComponentUuid);
massUpdate.execute((row, update) -> handleComponent(relations, row, update));
}
private void handleOrphans(Context context) throws SQLException {
MassUpdate massUpdate = context.prepareMassUpdate();
massUpdate.select("select uuid, project_uuid from projects where uuid_path is null");
massUpdate.update("update projects set uuid_path=? where uuid=? and uuid_path is null");
massUpdate.rowPluralName("orphan components");
massUpdate.execute((row, update, updateIndex) -> {
String uuid = row.getString(1);
String rootUuid = row.getString(2);
String path = uuid.equals(rootUuid) ? ROOT_PATH : (PATH_SEPARATOR + rootUuid + PATH_SEPARATOR);
update.setString(1, path);
update.setString(2, uuid);
return true;
});
}
private boolean handleComponent(Relations relations, Select.Row row, SqlStatement update) throws SQLException {
String componentUuid = row.getString(1);
String rootComponentUuid = row.getString(2);
if (componentUuid.equals(rootComponentUuid)) {
// Root component, no need to use the table SNAPSHOTS.
// Moreover it allows to support provisioned projects (zero analysis)
update.setString(1, PATH_SEPARATOR);
update.setString(2, componentUuid);
return true;
}
Snapshot snapshot = relations.snapshotsByComponentUuid.get(componentUuid);
if (snapshot == null) {
LOG.trace("No UUID found for component UUID={}", componentUuid);
return false;
}
List componentUuidPath = Arrays.stream(snapshot.snapshotPath)
.mapToObj(snapshotId -> relations.snapshotsById.get(snapshotId).componentUuid)
.collect(toCollection(() -> new ArrayList<>(snapshot.snapshotPath.length)));
update.setString(1, PATH_SEPARATOR + PATH_JOINER.join(componentUuidPath) + PATH_SEPARATOR);
update.setString(2, componentUuid);
return true;
}
private static final class Relations {
private final Map snapshotsByComponentUuid = new HashMap<>();
private final Map snapshotsById = new HashMap<>();
void add(Snapshot snapshot) {
snapshotsByComponentUuid.put(snapshot.componentUuid, snapshot);
snapshotsById.put(snapshot.id, snapshot);
}
}
private static final class Snapshot {
private static final long[] EMPTY_PATH = new long[0];
private final long id;
private final long[] snapshotPath;
private final String componentUuid;
public Snapshot(long id, String snapshotPath, String componentUuid) {
this.id = id;
this.snapshotPath = parsePath(snapshotPath);
this.componentUuid = componentUuid;
}
// inputs: null (on Oracle), "", "1." or "1.2.3."
private long[] parsePath(@Nullable String snapshotPath) {
if (snapshotPath == null) {
return EMPTY_PATH;
}
return PATH_SPLITTER
.splitToList(snapshotPath)
.stream()
.mapToLong(Long::parseLong)
.toArray();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy