}
private static boolean doTableExists(String table, Connection connection) {
- String schema = null;
-
- try {
- // Using H2 with a JDBC TCP connection is throwing an exception
- // See org.h2.engine.SessionRemote#getCurrentSchemaName()
- if (!"H2 JDBC Driver".equals(connection.getMetaData().getDriverName())) {
- schema = connection.getSchema();
- }
- } catch (SQLException e) {
- Loggers.get(DatabaseUtils.class).warn("Fail to determine schema. Keeping it null for searching tables", e);
- }
+ String schema = getSchema(connection);
// table type is used to speed-up Oracle by removing introspection of system tables and aliases.
try (ResultSet rs = connection.getMetaData().getTables(connection.getCatalog(), schema, table, TABLE_TYPE)) {
}
}
+ public static boolean indexExists(String table, String index, Connection connection) {
+ return doIndexExists(table, index, connection) ||
+ doIndexExists(table.toLowerCase(Locale.ENGLISH), index, connection) ||
+ doIndexExists(table.toUpperCase(Locale.ENGLISH), index, connection);
+ }
+
+ private static boolean doIndexExists(String table, String index, Connection connection) {
+ String schema = getSchema(connection);
+
+ try (ResultSet rs = connection.getMetaData().getIndexInfo(connection.getCatalog(), schema, table, false, true)) {
+ while (rs.next()) {
+ String indexName = rs.getString("INDEX_NAME");
+ if (index.equalsIgnoreCase(indexName)) {
+ return true;
+ }
+ }
+ return false;
+ } catch (SQLException e) {
+ throw wrapSqlException(e, "Can not check that table %s exists", table);
+ }
+ }
+
+ @CheckForNull
+ private static String getSchema(Connection connection) {
+ String schema = null;
+
+ try {
+ // Using H2 with a JDBC TCP connection is throwing an exception
+ // See org.h2.engine.SessionRemote#getCurrentSchemaName()
+ if (!"H2 JDBC Driver".equals(connection.getMetaData().getDriverName())) {
+ schema = connection.getSchema();
+ }
+ } catch (SQLException e) {
+ Loggers.get(DatabaseUtils.class).warn("Fail to determine schema. Keeping it null for searching tables", e);
+ }
+ return schema;
+ }
+
public static IllegalStateException wrapSqlException(SQLException e, String message, Object... messageArgs) {
return new IllegalStateException(format(message, messageArgs), e);
}
}
public void assertTableDoesNotExist(String table) {
+ assertTableExists(table, false);
+ }
+
+ public void assertTableExists(String table) {
+ assertTableExists(table, true);
+ }
+
+ private void assertTableExists(String table, boolean expected) {
try (Connection connection = getConnection()) {
boolean tableExists = DatabaseUtils.tableExists(table, connection);
- assertThat(tableExists).isFalse();
+ assertThat(tableExists).isEqualTo(expected);
} catch (Exception e) {
throw new IllegalStateException("Fail to check if table exists", e);
}
*/
package org.sonar.server.platform.db.migration.sql;
+import java.sql.Connection;
+import java.sql.SQLException;
import java.util.List;
+import org.sonar.db.Database;
+import org.sonar.db.DatabaseUtils;
import org.sonar.db.dialect.Dialect;
import org.sonar.db.dialect.H2;
import org.sonar.db.dialect.MsSql;
}
}
+ public boolean indexExists(Database database) throws SQLException {
+ validateTableName(tableName);
+ validateIndexName(indexName);
+ try (Connection connection = database.getDataSource().getConnection()) {
+ return DatabaseUtils.indexExists(tableName, indexName, connection);
+ }
+ }
}
protected abstract void execute(Context context) throws SQLException;
- private Connection createReadUncommittedConnection() throws SQLException {
+ protected Connection createReadUncommittedConnection() throws SQLException {
Connection connection = db.getDataSource().getConnection();
connection.setAutoCommit(false);
if (connection.getMetaData().supportsTransactionIsolationLevel(Connection.TRANSACTION_READ_UNCOMMITTED)) {
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info 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.server.platform.db.migration.version.v70;
+
+import java.sql.SQLException;
+import org.sonar.db.Database;
+import org.sonar.server.platform.db.migration.sql.CreateIndexBuilder;
+import org.sonar.server.platform.db.migration.step.DdlChange;
+
+import static org.sonar.server.platform.db.migration.def.IntegerColumnDef.newIntegerColumnDefBuilder;
+import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.UUID_VARCHAR_SIZE;
+import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.newVarcharColumnDefBuilder;
+
+/**
+ * Add this index only once table is populated to improve efficiency of populating the table.
+ */
+public class AddLiveMeasuresMetricIndex extends DdlChange {
+
+ private static final String TABLE_NAME = "live_measures";
+
+ public AddLiveMeasuresMetricIndex(Database db) {
+ super(db);
+ }
+
+ @Override
+ public void execute(Context context) throws SQLException {
+ context.execute(new CreateIndexBuilder(getDialect())
+ .addColumn(newVarcharColumnDefBuilder()
+ .setColumnName("component_uuid")
+ .setIsNullable(false)
+ .setLimit(UUID_VARCHAR_SIZE)
+ .build())
+ .addColumn(newIntegerColumnDefBuilder()
+ .setColumnName("metric_id")
+ .setIsNullable(false)
+ .build())
+ .setUnique(true)
+ .setTable(TABLE_NAME)
+ .setName("live_measures_component")
+ .build());
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info 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.server.platform.db.migration.version.v70;
+
+import java.sql.SQLException;
+import org.sonar.db.Database;
+import org.sonar.server.platform.db.migration.sql.CreateIndexBuilder;
+import org.sonar.server.platform.db.migration.step.DdlChange;
+
+import static org.sonar.server.platform.db.migration.def.BooleanColumnDef.newBooleanColumnDefBuilder;
+
+public class AddSnapshotIsLastIndex extends DdlChange {
+ static final String TABLE_NAME = "snapshots";
+ static final String INDEX_NAME = "ix_snapshot_is_last";
+
+ public AddSnapshotIsLastIndex(Database db) {
+ super(db);
+ }
+
+ @Override
+ public void execute(Context context) throws SQLException {
+ context.execute(
+ new CreateIndexBuilder(getDialect())
+ .setTable(TABLE_NAME)
+ .setName(INDEX_NAME)
+ .setUnique(false)
+ .addColumn(newBooleanColumnDefBuilder().setColumnName("islast").setIsNullable(false).setDefaultValue(false).build())
+ .build());
+ }
+}
import static org.sonar.server.platform.db.migration.def.DecimalColumnDef.newDecimalColumnDefBuilder;
import static org.sonar.server.platform.db.migration.def.IntegerColumnDef.newIntegerColumnDefBuilder;
import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.UUID_SIZE;
+import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.UUID_VARCHAR_SIZE;
import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.newVarcharColumnDefBuilder;
public class CreateTableLiveMeasures extends DdlChange {
@Override
public void execute(Context context) throws SQLException {
+ VarcharColumnDef projectUuidCol = newVarcharColumnDefBuilder()
+ .setColumnName("project_uuid")
+ .setIsNullable(false)
+ .setLimit(UUID_VARCHAR_SIZE)
+ .build();
+
context.execute(new CreateTableBuilder(getDialect(), TABLE_NAME)
.addPkColumn(newVarcharColumnDefBuilder()
.setColumnName("uuid")
.setIsNullable(false)
.setLimit(VarcharColumnDef.UUID_SIZE)
.build())
- .addColumn(newVarcharColumnDefBuilder()
- .setColumnName("project_uuid")
- .setIsNullable(false)
- .setLimit(VarcharColumnDef.UUID_VARCHAR_SIZE)
- .build())
+ .addColumn(projectUuidCol)
.addColumn(newVarcharColumnDefBuilder()
.setColumnName("component_uuid")
.setIsNullable(false)
- .setLimit(VarcharColumnDef.UUID_VARCHAR_SIZE)
+ .setLimit(UUID_VARCHAR_SIZE)
.build())
.addColumn(newIntegerColumnDefBuilder()
.setColumnName("metric_id")
.build());
context.execute(new CreateIndexBuilder(getDialect())
- .addColumn(newVarcharColumnDefBuilder()
- .setColumnName("project_uuid")
- .setIsNullable(false)
- .setLimit(VarcharColumnDef.UUID_VARCHAR_SIZE)
- .build())
+ .addColumn(projectUuidCol)
.setUnique(false)
.setTable(TABLE_NAME)
.setName("live_measures_project")
.build());
-
- context.execute(new CreateIndexBuilder(getDialect())
- .addColumn(newVarcharColumnDefBuilder()
- .setColumnName("component_uuid")
- .setIsNullable(false)
- .setLimit(VarcharColumnDef.UUID_VARCHAR_SIZE)
- .build())
- .addColumn(newIntegerColumnDefBuilder()
- .setColumnName("metric_id")
- .setIsNullable(false)
- .build())
- .setUnique(true)
- .setTable(TABLE_NAME)
- .setName("live_measures_component")
- .build());
}
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info 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.server.platform.db.migration.version.v70;
+
+import java.sql.SQLException;
+import org.sonar.db.Database;
+import org.sonar.server.platform.db.migration.def.VarcharColumnDef;
+import org.sonar.server.platform.db.migration.sql.CreateTableBuilder;
+import org.sonar.server.platform.db.migration.step.DdlChange;
+
+import static org.sonar.server.platform.db.migration.def.VarcharColumnDef.UUID_VARCHAR_SIZE;
+
+public class CreateTempTableLiveMeasuresP extends DdlChange {
+
+ static final String TABLE_NAME = "live_measures_p";
+
+ public CreateTempTableLiveMeasuresP(Database db) {
+ super(db);
+ }
+
+ @Override
+ public void execute(Context context) throws SQLException {
+ CreateTableBuilder builder = new CreateTableBuilder(getDialect(), TABLE_NAME);
+ if (!builder.tableExists(getDatabase())) {
+ context.execute(builder
+ .addPkColumn(new VarcharColumnDef.Builder()
+ .setColumnName("project_uuid")
+ .setLimit(UUID_VARCHAR_SIZE)
+ .setIsNullable(false)
+ .setIgnoreOracleUnit(true)
+ .build())
+ .build());
+ }
+ }
+}
@Override
public void addSteps(MigrationStepRegistry registry) {
registry
- .add(1900, "Add QUALITY_GATES.IS_BUILT_IN", AddIsBuiltInToQualityGates.class)
- .add(1901, "Populate QUALITY_GATES.IS_BUILT_IN", PopulateQualityGatesIsBuiltIn.class)
- .add(1902, "Make QUALITY_GATES.IS_BUILT_IN not null", MakeQualityGatesIsBuiltInNotNullable.class)
- .add(1903, "Remove quality gates loaded templates", RemoveQualityGateLoadedTemplates.class)
- .add(1904, "Rename quality gate \"SonarQube way\" to \"Sonar way\"", RenameOldSonarQubeWayQualityGate.class)
- .add(1905, "Drop LOADED_TEMPLATES table", DropLoadedTemplatesTable.class)
- .add(1906, "Create table live_measures", CreateTableLiveMeasures.class)
- .add(1907, "Populate table live_measures", PopulateLiveMeasures.class)
- .add(1908, "Delete person and file measures", DeletePersonAndFileMeasures.class)
- .add(1909, "Drop index on project_measures.person_id", DropIndexOnPersonMeasures.class)
- .add(1910, "Create ORG_QUALITY_GATES table", CreateOrgQualityGatesTable.class)
- .add(1911, "Add ORGANIZATIONS.DEFAULT_QUALITY_GATE_UUID", AddDefaultQualityGateUuidToOrganizations.class)
- .add(1912, "Create QUALITY_GATES.UUID", AddUuidToQualityGates.class)
- .add(1913, "Populate QUALITY_GATES.UUID", PopulateUuidOnQualityGates.class)
- .add(1914, "Make QUALITY_GATES.UUID not nullable", MakeUuidNotNullableOnQualityGates.class)
- .add(1915, "Drop unique index on QUALITY_GATES.NAME", DropUniqueIndexOnQualityGatesName.class)
- .add(1916, "Create builtin quality gate if required", CreateBuiltInQualityGate.class)
- .add(1917, "Populate ORG_QUALITY_GATES table", PopulateOrgQualityGates.class)
- .add(1918, "Populate default quality gate on organization", PopulateDefaultQualityGate.class)
- .add(1919, "Associate existing quality gates to default organization", AssociateQualityGatesToDefaultOrganization.class)
- .add(1920, "Read 'sonar.qualitygate' setting and set the value to default organization", ReadGlobalSonarQualityGateSettingToDefaultOrg.class)
- .add(1921, "Delete 'sonar.qualitygate' setting at global level", DeleteGlobalSonarQualityGateSetting.class)
- .add(1922, "Make ORGANIZATIONS.DEFAULT_QUALITY_GATE_UUID not nullable", SetDefaultQualityGateUuidAsNotNullableInOrganizations.class)
- .add(1923, "Add users.homepage_type and users.homepage_parameter", AddHomepageToUsers.class)
+ .add(1930, "Add QUALITY_GATES.IS_BUILT_IN", AddIsBuiltInToQualityGates.class)
+ .add(1931, "Populate QUALITY_GATES.IS_BUILT_IN", PopulateQualityGatesIsBuiltIn.class)
+ .add(1932, "Make QUALITY_GATES.IS_BUILT_IN not null", MakeQualityGatesIsBuiltInNotNullable.class)
+ .add(1933, "Remove quality gates loaded templates", RemoveQualityGateLoadedTemplates.class)
+ .add(1934, "Rename quality gate \"SonarQube way\" to \"Sonar way\"", RenameOldSonarQubeWayQualityGate.class)
+ .add(1935, "Drop LOADED_TEMPLATES table", DropLoadedTemplatesTable.class)
+
+ // optimizations of migrations from 7.0 on project_measures and live_measures
+ .add(1936, "Delete person measures", DeletePersonMeasures.class)
+ .add(1937, "Drop index on project_measures.person_id", DropIndexOnPersonMeasures.class)
+ .add(1938, "Create table live_measures", CreateTableLiveMeasures.class)
+ .add(1939, "Add temporary index on SNAPSHOTS.ISLAST", AddSnapshotIsLastIndex.class)
+ .add(1940," Create temporary table LIVE_MEASURES_P", CreateTempTableLiveMeasuresP.class)
+ .add(1941, "Populate table live_measures", PopulateLiveMeasures.class)
+ .add(1942, "Add live_measures.metric_id index", AddLiveMeasuresMetricIndex.class)
+ .add(1943, "Drop temporary table LIVE_MEASURES_P", DropTempTableLiveMeasuresP.class)
+ .add(1944, "Drop temporary index on SNAPSHOTS.ISLAST", DropSnapshotIsLastIndex.class)
+ .add(1945, "Delete file measures", DeleteFileMeasures.class)
+
+ .add(1946, "Create ORG_QUALITY_GATES table", CreateOrgQualityGatesTable.class)
+ .add(1947, "Add ORGANIZATIONS.DEFAULT_QUALITY_GATE_UUID", AddDefaultQualityGateUuidToOrganizations.class)
+ .add(1948, "Create QUALITY_GATES.UUID", AddUuidToQualityGates.class)
+ .add(1949, "Populate QUALITY_GATES.UUID", PopulateUuidOnQualityGates.class)
+ .add(1950, "Make QUALITY_GATES.UUID not nullable", MakeUuidNotNullableOnQualityGates.class)
+ .add(1951, "Drop unique index on QUALITY_GATES.NAME", DropUniqueIndexOnQualityGatesName.class)
+ .add(1952, "Create builtin quality gate if required", CreateBuiltInQualityGate.class)
+ .add(1953, "Populate ORG_QUALITY_GATES table", PopulateOrgQualityGates.class)
+ .add(1954, "Populate default quality gate on organization", PopulateDefaultQualityGate.class)
+ .add(1955, "Associate existing quality gates to default organization", AssociateQualityGatesToDefaultOrganization.class)
+ .add(1956, "Read 'sonar.qualitygate' setting and set the value to default organization", ReadGlobalSonarQualityGateSettingToDefaultOrg.class)
+ .add(1957, "Delete 'sonar.qualitygate' setting at global level", DeleteGlobalSonarQualityGateSetting.class)
+ .add(1958, "Make ORGANIZATIONS.DEFAULT_QUALITY_GATE_UUID not nullable", SetDefaultQualityGateUuidAsNotNullableInOrganizations.class)
+ .add(1959, "Add users.homepage_type and users.homepage_parameter", AddHomepageToUsers.class)
;
}
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info 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.server.platform.db.migration.version.v70;
+
+import java.sql.SQLException;
+import org.sonar.db.Database;
+import org.sonar.server.platform.db.migration.step.DataChange;
+import org.sonar.server.platform.db.migration.step.MassUpdate;
+
+public class DeleteFileMeasures extends DataChange {
+
+ public DeleteFileMeasures(Database db) {
+ super(db);
+ }
+
+ @Override
+ protected void execute(Context context) throws SQLException {
+ MassUpdate massUpdate = context.prepareMassUpdate();
+ massUpdate.select("select c.uuid from projects c where c.qualifier = 'UTS' or c.qualifier = 'FIL'");
+ massUpdate.rowPluralName("files");
+ massUpdate.update("delete from project_measures pm where pm.component_uuid=?")
+ .setBatchSize(10);
+
+ massUpdate.execute((row, update) -> {
+ String componentUuid = row.getString(1);
+ update.setString(1, componentUuid);
+ return true;
+ });
+ }
+
+}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info 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.server.platform.db.migration.version.v70;
-
-import java.sql.SQLException;
-import org.sonar.api.config.Configuration;
-import org.sonar.db.Database;
-import org.sonar.db.dialect.H2;
-import org.sonar.db.dialect.MsSql;
-import org.sonar.db.dialect.MySql;
-import org.sonar.db.dialect.Oracle;
-import org.sonar.db.dialect.PostgreSql;
-import org.sonar.server.platform.db.migration.step.DataChange;
-import org.sonar.server.platform.db.migration.step.MassUpdate;
-
-public class DeletePersonAndFileMeasures extends DataChange {
-
- private final Configuration configuration;
-
- public DeletePersonAndFileMeasures(Database db, Configuration configuration) {
- super(db);
- this.configuration = configuration;
- }
-
- @Override
- protected void execute(Context context) throws SQLException {
- if (configuration.getBoolean("sonar.sonarcloud.enabled").orElse(false)) {
- // clean-up will be done in background so that interruption of service
- // is reduced during upgrade
- return;
- }
- MassUpdate massUpdate = context.prepareMassUpdate();
- massUpdate.select("select uuid from snapshots");
- massUpdate.rowPluralName("snapshots");
- massUpdate.update(getDeleteSql()).setBatchSize(1);
-
- massUpdate.execute((row, update) -> {
- String analysisUuid = row.getString(1);
- update.setString(1, analysisUuid);
- if (getDialect().getId().equals(Oracle.ID)) {
- update.setString(2, analysisUuid);
- }
- return true;
- });
- }
-
- private String getDeleteSql() {
- switch (getDialect().getId()) {
- case MySql.ID:
- case MsSql.ID:
- return "delete pm from project_measures pm " +
- "inner join projects c on c.uuid = pm.component_uuid " +
- "where pm.analysis_uuid = ? " +
- "and (c.qualifier in ('UTS', 'FIL') or pm.person_id is not null)";
- case H2.ID:
- return "delete from project_measures " +
- "where id in ( " +
- " select pm.id from project_measures pm " +
- " inner join projects c on c.uuid = pm.component_uuid " +
- " where pm.analysis_uuid = ? " +
- " and (c.qualifier in ('UTS', 'FIL') or pm.person_id is not null) " +
- ")";
- case PostgreSql.ID:
- return "delete from project_measures pm " +
- "using projects c " +
- "where pm.analysis_uuid = ? " +
- "and c.uuid = pm.component_uuid " +
- "and (c.qualifier in ('UTS', 'FIL') or pm.person_id is not null) ";
- case Oracle.ID:
- return "delete from project_measures pm where exists (" +
- " select 1 from project_measures pm2 " +
- " inner join projects c on c.uuid = pm2.component_uuid " +
- " where pm2.analysis_uuid = ? " +
- " and (c.qualifier in ('UTS', 'FIL') or pm.person_id is not null) " +
- " and pm.id = pm2.id" +
- ") and pm.analysis_uuid = ?";
- default:
- throw new IllegalStateException("Unsupported DB dialect: " + getDialect());
- }
- }
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info 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.server.platform.db.migration.version.v70;
+
+import java.sql.SQLException;
+import org.sonar.db.Database;
+import org.sonar.db.dialect.H2;
+import org.sonar.db.dialect.MsSql;
+import org.sonar.db.dialect.MySql;
+import org.sonar.db.dialect.Oracle;
+import org.sonar.db.dialect.PostgreSql;
+import org.sonar.server.platform.db.migration.step.DataChange;
+import org.sonar.server.platform.db.migration.step.MassUpdate;
+
+public class DeletePersonMeasures extends DataChange {
+
+ public DeletePersonMeasures(Database db) {
+ super(db);
+ }
+
+ @Override
+ protected void execute(Context context) throws SQLException {
+ MassUpdate massUpdate = context.prepareMassUpdate();
+ massUpdate.select("select uuid from snapshots");
+ massUpdate.rowPluralName("snapshots");
+ massUpdate.update(getDeleteSql()).setBatchSize(1);
+
+ massUpdate.execute((row, update) -> {
+ String analysisUuid = row.getString(1);
+ update.setString(1, analysisUuid);
+ if (getDialect().getId().equals(Oracle.ID)) {
+ update.setString(2, analysisUuid);
+ }
+ return true;
+ });
+ }
+
+ private String getDeleteSql() {
+ switch (getDialect().getId()) {
+ case MySql.ID:
+ case MsSql.ID:
+ return "delete pm from project_measures pm " +
+ "inner join projects c on c.uuid = pm.component_uuid " +
+ "where pm.analysis_uuid = ? " +
+ "and pm.person_id is not null";
+ case H2.ID:
+ return "delete from project_measures " +
+ "where id in ( " +
+ " select pm.id from project_measures pm " +
+ " inner join projects c on c.uuid = pm.component_uuid " +
+ " where pm.analysis_uuid = ? " +
+ " and pm.person_id is not null" +
+ ")";
+ case PostgreSql.ID:
+ return "delete from project_measures pm " +
+ "using projects c " +
+ "where pm.analysis_uuid = ? " +
+ "and c.uuid = pm.component_uuid " +
+ "and pm.person_id is not null";
+ case Oracle.ID:
+ return "delete from project_measures pm where exists (" +
+ " select 1 from project_measures pm2 " +
+ " inner join projects c on c.uuid = pm2.component_uuid " +
+ " where pm2.analysis_uuid = ? " +
+ " and pm.person_id is not null " +
+ " and pm.id = pm2.id" +
+ ") and pm.analysis_uuid = ?";
+ default:
+ throw new IllegalStateException("Unsupported DB dialect: " + getDialect());
+ }
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info 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.server.platform.db.migration.version.v70;
+
+import java.sql.SQLException;
+import org.sonar.db.Database;
+import org.sonar.server.platform.db.migration.sql.DropIndexBuilder;
+import org.sonar.server.platform.db.migration.step.DdlChange;
+
+public class DropSnapshotIsLastIndex extends DdlChange {
+ public DropSnapshotIsLastIndex(Database db) {
+ super(db);
+ }
+
+ @Override
+ public void execute(Context context) throws SQLException {
+ context.execute(
+ new DropIndexBuilder(getDialect())
+ .setTable(AddSnapshotIsLastIndex.TABLE_NAME)
+ .setName(AddSnapshotIsLastIndex.INDEX_NAME)
+ .build());
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info 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.server.platform.db.migration.version.v70;
+
+import java.sql.SQLException;
+import org.sonar.db.Database;
+import org.sonar.server.platform.db.migration.sql.CreateTableBuilder;
+import org.sonar.server.platform.db.migration.sql.DropTableBuilder;
+import org.sonar.server.platform.db.migration.step.DdlChange;
+
+public class DropTempTableLiveMeasuresP extends DdlChange {
+ public DropTempTableLiveMeasuresP(Database db) {
+ super(db);
+ }
+
+ @Override
+ public void execute(Context context) throws SQLException {
+ if (new CreateTableBuilder(getDialect(), CreateTempTableLiveMeasuresP.TABLE_NAME).tableExists(getDatabase())) {
+ DropTableBuilder builder = new DropTableBuilder(getDialect(), CreateTempTableLiveMeasuresP.TABLE_NAME);
+ context.execute(builder.build());
+ }
+ }
+}
*/
package org.sonar.server.platform.db.migration.version.v70;
+import java.sql.Connection;
import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+import javax.annotation.concurrent.Immutable;
import org.sonar.api.utils.System2;
+import org.sonar.api.utils.log.Logger;
+import org.sonar.api.utils.log.Loggers;
import org.sonar.core.util.Uuids;
import org.sonar.db.Database;
import org.sonar.server.platform.db.migration.step.DataChange;
import org.sonar.server.platform.db.migration.step.MassUpdate;
+import org.sonar.server.platform.db.migration.step.Select;
+import org.sonar.server.platform.db.migration.step.SelectImpl;
+import org.sonar.server.platform.db.migration.step.SqlStatement;
+import org.sonar.server.platform.db.migration.step.Upsert;
+
+import static java.util.stream.Collectors.joining;
public class PopulateLiveMeasures extends DataChange {
+ private static final Logger LOG = Loggers.get(PopulateLiveMeasures.class);
private final System2 system2;
+ private final Database db;
public PopulateLiveMeasures(Database db, System2 system2) {
super(db);
+ this.db = db;
this.system2 = system2;
}
@Override
protected void execute(Context context) throws SQLException {
+ boolean firstAttempt = context.prepareSelect("select count(1) from live_measures_p")
+ .get(t -> t.getLong(1)) == 0;
+ if (!firstAttempt) {
+ LOG.info("Retry detected (non empty table live_measures_p). Handle it");
+ }
+
long now = system2.now();
- // reentrancy of migration
- context.prepareUpsert("TRUNCATE TABLE live_measures").execute();
+ int projectBatchSize = 10;
+ String statement = "" +
+ " select" +
+ " s.uuid, s.component_uuid" +
+ " from snapshots s" +
+ " where" +
+ " s.islast = ?" +
+ (firstAttempt ? "" : " and not exists (select 1 from live_measures_p lmp where lmp.project_uuid=s.component_uuid)");
+ try (Connection connection = createReadUncommittedConnection();
+ Select select = SelectImpl.create(db, connection, statement).setBoolean(1, true)) {
+ List<Row> rows = new ArrayList<>(projectBatchSize);
+ select.scroll(t -> {
+ rows.add(new Row(t.getString(1), t.getString(2)));
+ if (rows.size() == projectBatchSize) {
+ processProjectBatch(context, rows, firstAttempt, now);
- MassUpdate massUpdate = context.prepareMassUpdate();
- massUpdate.select("SELECT p.uuid, p.project_uuid, pm.metric_id, pm.value, pm.text_value, pm.variation_value_1, pm.measure_data " +
- "FROM project_measures pm " +
- "INNER JOIN projects p on p.uuid = pm.component_uuid " +
- "INNER JOIN snapshots s on s.uuid = pm.analysis_uuid " +
- "WHERE s.islast = ? and pm.person_id is null")
- .setBoolean(1, true);
+ rows.clear();
+ }
+ });
- massUpdate.update("INSERT INTO live_measures "
- + "(uuid, component_uuid, project_uuid, metric_id, value, text_value, variation, measure_data, created_at, updated_at) "
- + "values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
+ if (!rows.isEmpty()) {
+ processProjectBatch(context, rows, firstAttempt, now);
+ }
+ }
+ }
+ private static void processProjectBatch(Context context, List<Row> rows, boolean firstAttempt, long now) throws SQLException {
+ MassUpdate massUpdate = context.prepareMassUpdate();
massUpdate.rowPluralName("live measures");
- massUpdate.execute((row, update) -> {
+ setSelect(rows, massUpdate);
+ massUpdate.update("delete from live_measures where project_uuid=?");
+ massUpdate.update(" insert into live_measures" +
+ " (uuid, component_uuid, project_uuid, metric_id, value, text_value, variation, measure_data, created_at, updated_at)" +
+ " values" +
+ " (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
+ massUpdate.update("insert into live_measures_p (project_uuid) values (?)");
+ LiveMeasurePopulationMultiHandler handler = new LiveMeasurePopulationMultiHandler(firstAttempt, rows, now);
+ massUpdate.execute(handler);
+
+ Set<String> notCommittedProjectUuids = handler.notCommittedProjectUuids;
+ if (!notCommittedProjectUuids.isEmpty()) {
+ Upsert upsert = context.prepareUpsert("insert into live_measures_p (project_uuid) values (?)");
+ for (String projectUuid : notCommittedProjectUuids) {
+ upsert.setString(1, projectUuid);
+ upsert.execute();
+ }
+ upsert.commit();
+ }
+ }
+
+ private static void setSelect(List<Row> rows, MassUpdate massUpdate) throws SQLException {
+ String questionMarks = rows.stream().map(t -> "?").collect(joining(",", "(", ")"));
+ SqlStatement select = massUpdate.select("" +
+ " select" +
+ " p.project_uuid, pm.component_uuid, pm.metric_id, pm.value, pm.text_value, pm.variation_value_1, pm.measure_data" +
+ " from project_measures pm" +
+ " inner join projects p on p.uuid = pm.component_uuid and p.project_uuid in " + questionMarks +
+ " where" +
+ " pm.analysis_uuid in " + questionMarks +
+ " order by" +
+ " p.project_uuid");
+ int i = 1;
+ for (Row row : rows) {
+ select.setString(i, row.getProjectUuid());
+ i++;
+ }
+ for (Row row : rows) {
+ select.setString(i, row.getAnalysisUuid());
+ i++;
+ }
+ }
+
+ private static class LiveMeasurePopulationMultiHandler implements MassUpdate.MultiHandler {
+ private final boolean firstAttempt;
+ private final long now;
+ private final Set<String> notCommittedProjectUuids;
+ private String deletePreviousProjectUuid = null;
+ private String currentProjectUuid = null;
+
+ private LiveMeasurePopulationMultiHandler(boolean firstAttempt, List<Row> rows, long now) {
+ this.firstAttempt = firstAttempt;
+ this.now = now;
+ this.notCommittedProjectUuids = rows.stream().map(Row::getProjectUuid).collect(Collectors.toSet());
+ }
+
+ @Override
+ public boolean handle(Select.Row row, SqlStatement update, int updateIndex) throws SQLException {
+ String projectUuid = row.getString(1);
+ switch (updateIndex) {
+ case 0:
+ return doRentranceDelete(update, projectUuid);
+ case 1:
+ return doLiveMeasureInsert(row, update, projectUuid);
+ case 2:
+ return doComponentDoneInsert(update, projectUuid);
+ default:
+ throw new IllegalStateException("Unsupported update index" + updateIndex);
+ }
+ }
+
+ private boolean doRentranceDelete(SqlStatement update, String projectUuid) throws SQLException {
+ if (firstAttempt) {
+ return false;
+ }
+
+ if (deletePreviousProjectUuid == null || !deletePreviousProjectUuid.equals(projectUuid)) {
+ update.setString(1, projectUuid);
+ deletePreviousProjectUuid = projectUuid;
+ return true;
+ }
+ return false;
+ }
+
+ private boolean doLiveMeasureInsert(Select.Row row, SqlStatement update, String projectUuid) throws SQLException {
update.setString(1, Uuids.create());
- update.setString(2, row.getString(1));
- update.setString(3, row.getString(2));
+ update.setString(2, row.getString(2));
+ update.setString(3, projectUuid);
update.setInt(4, row.getInt(3));
update.setDouble(5, row.getNullableDouble(4));
update.setString(6, row.getNullableString(5));
update.setLong(9, now);
update.setLong(10, now);
return true;
- });
+ }
+
+ /**
+ * When currentProjectUuid changes, we know we are done will all the measures for this component and therefor
+ * can insert it into live_measures_p.
+ * <p>
+ * <strong>This requires statement selecting measures to be sorted by project_uuid and then component_uuid.</strong>
+ */
+ private boolean doComponentDoneInsert(SqlStatement update, String projectUuid) throws SQLException {
+ if (currentProjectUuid == null || currentProjectUuid.equals(projectUuid)) {
+ this.currentProjectUuid = projectUuid;
+ return false;
+ }
+ update.setString(1, currentProjectUuid);
+ this.notCommittedProjectUuids.remove(currentProjectUuid);
+ this.currentProjectUuid = projectUuid;
+ return true;
+ }
+
}
+ @Immutable
+ private static final class Row {
+ private final String analysisUuid;
+ private final String projectUuid;
+
+ private Row(String analysisUuid, String projectUuid) {
+ this.analysisUuid = analysisUuid;
+ this.projectUuid = projectUuid;
+ }
+
+ public String getAnalysisUuid() {
+ return analysisUuid;
+ }
+
+ public String getProjectUuid() {
+ return projectUuid;
+ }
+
+ @Override
+ public String toString() {
+ return "Row{" +
+ "analysisUuid='" + analysisUuid + '\'' +
+ ", projectUuid='" + projectUuid + '\'' +
+ '}';
+ }
+ }
}
// DbVersion classes
+ 20
// Others
- + 3);
+ + 4);
}
}
*/
package org.sonar.server.platform.db.migration.history;
-import java.sql.SQLException;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.db.CoreDbTester;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
public class NoTableMigrationHistoryImplTest {
@Rule
public CoreDbTester dbTester = CoreDbTester.createEmpty();
@Rule
public ExpectedException expectedException = ExpectedException.none();
- private MigrationHistoryImpl underTest = new MigrationHistoryImpl(dbTester.database());
+ private MigrationHistoryMeddler migrationHistoryMeddler = mock(MigrationHistoryMeddler.class);
+ private MigrationHistoryImpl underTest = new MigrationHistoryImpl(dbTester.database(), migrationHistoryMeddler);
@Test
public void start_fails_with_ISE_if_table_history_does_not_exist() {
expectedException.expectMessage("Migration history table is missing");
underTest.start();
+
+ verifyZeroInteractions(migrationHistoryMeddler);
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info 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.server.platform.db.migration.version.v70;
+
+import java.sql.SQLException;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.db.CoreDbTester;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class AddLiveMeasuresMetricIndexTest {
+ private static final String TABLE = "live_measures";
+
+ @Rule
+ public final CoreDbTester db = CoreDbTester.createForSchema(AddLiveMeasuresMetricIndexTest.class, "live_measures.sql");
+
+ private AddLiveMeasuresMetricIndex underTest = new AddLiveMeasuresMetricIndex(db.database());
+
+ @Test
+ public void creates_table_on_empty_db() throws SQLException {
+ underTest.execute();
+
+ assertThat(db.countRowsOfTable(TABLE)).isEqualTo(0);
+
+ db.assertUniqueIndex(TABLE, "live_measures_component", "component_uuid", "metric_id");
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info 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.server.platform.db.migration.version.v70;
+
+import java.sql.SQLException;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.db.CoreDbTester;
+
+public class AddSnapshotIsLastIndexTest {
+ @Rule
+ public final CoreDbTester dbTester = CoreDbTester.createForSchema(AddSnapshotIsLastIndexTest.class, "snapshots.sql");
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ private AddSnapshotIsLastIndex underTest = new AddSnapshotIsLastIndex(dbTester.database());
+
+ @Test
+ public void add_index_on_snapshots_islast_column() throws SQLException {
+ underTest.execute();
+
+ dbTester.assertIndex("snapshots", "ix_snapshot_is_last", "islast");
+ }
+
+ @Test
+ public void migration_is_not_reentrant() throws SQLException {
+ underTest.execute();
+
+ expectedException.expect(IllegalStateException.class);
+
+ underTest.execute();
+ }
+}
db.assertColumnDefinition(TABLE, "updated_at", Types.BIGINT, null, false);
db.assertIndex(TABLE, "live_measures_project", "project_uuid");
- db.assertUniqueIndex(TABLE, "live_measures_component", "component_uuid", "metric_id");
}
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info 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.server.platform.db.migration.version.v70;
+
+import java.sql.SQLException;
+import java.sql.Types;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.db.CoreDbTester;
+
+public class CreateTempTableLiveMeasuresPTest {
+ @Rule
+ public final CoreDbTester dbTester = CoreDbTester.createForSchema(CreateTempTableLiveMeasuresPTest.class, "empty.sql");
+
+ @Rule
+ public ExpectedException expectedException = ExpectedException.none();
+
+ private CreateTempTableLiveMeasuresP underTest = new CreateTempTableLiveMeasuresP(dbTester.database());
+
+ @Test
+ public void create_table_live_measures_p() throws SQLException {
+ underTest.execute();
+
+ dbTester.assertColumnDefinition("live_measures_p", "project_uuid", Types.VARCHAR, 50, false);
+ dbTester.assertPrimaryKey("live_measures_p", "pk_live_measures_p", "project_uuid");
+ }
+
+ @Test
+ public void migration_is_reentrant() throws SQLException {
+ underTest.execute();
+
+ underTest.execute();
+ }
+}
@Test
public void migrationNumber_starts_at_1900() {
- verifyMinimumMigrationNumber(underTest, 1900);
+ verifyMinimumMigrationNumber(underTest, 1930);
}
@Test
public void verify_migration_count() {
- verifyMigrationCount(underTest, 24);
+ verifyMigrationCount(underTest, 30);
}
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info 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.server.platform.db.migration.version.v70;
+
+import java.sql.SQLException;
+import java.util.concurrent.atomic.AtomicInteger;
+import org.apache.commons.lang.math.RandomUtils;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.db.CoreDbTester;
+import org.sonar.server.platform.db.migration.step.DataChange;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class DeleteFileMeasuresTest {
+ private static final AtomicInteger GENERATOR = new AtomicInteger();
+
+ @Rule
+ public CoreDbTester db = CoreDbTester.createForSchema(DeleteFileMeasuresTest.class, "initial.sql");
+
+ private DataChange underTest = new DeleteFileMeasures(db.database());
+
+ @Test
+ public void delete_file_and_person_measures() throws SQLException {
+ String projectUuid = "P1";
+ insertComponent(projectUuid, projectUuid, "PRJ", "TRK");
+ insertComponent("D1", projectUuid, "DIR", "DIR");
+ insertComponent("F1", projectUuid, "FIL", "FIL");
+ insertComponent("F2", projectUuid, "FIL", "UTS");
+ insertSnapshot("S1", projectUuid, false);
+ insertSnapshot("S2", projectUuid, true);
+ // past measures
+ long m1 = insertMeasure(projectUuid, "S1");
+ long m2 = insertMeasure("D1", "S1");
+ long m3 = insertMeasure("F1", "S1");
+ long m4 = insertMeasure("F2", "S1");
+ long m5 = insertPersonMeasure(projectUuid, "S1");
+ long m6 = insertPersonMeasure("F1", "S1");
+ // last measures
+ long m7 = insertMeasure(projectUuid, "S2");
+ long m8 = insertMeasure("D1", "S2");
+ long m9 = insertMeasure("F1", "S2");
+ long m10 = insertMeasure("F2", "S2");
+ long m11 = insertPersonMeasure(projectUuid, "S2");
+ long m12 = insertPersonMeasure("F1", "S2");
+
+ underTest.execute();
+
+ assertThat(db.countRowsOfTable("PROJECTS")).isEqualTo(4);
+ assertThat(db.countRowsOfTable("SNAPSHOTS")).isEqualTo(2);
+ assertThatMeasuresAreExactly(m1, m2, m5, m7, m8, m11);
+
+ // migration is re-entrant
+ underTest.execute();
+ assertThat(db.countRowsOfTable("PROJECTS")).isEqualTo(4);
+ assertThat(db.countRowsOfTable("SNAPSHOTS")).isEqualTo(2);
+ assertThatMeasuresAreExactly(m1, m2, m7, m5, m8, m11);
+ }
+
+ private void assertThatMeasuresAreExactly(long... expectedMeasureIds) {
+ long[] ids = db.select("select id as \"id\" from project_measures")
+ .stream()
+ .mapToLong(m -> (Long) m.get("id"))
+ .toArray();
+ assertThat(ids).containsOnly(expectedMeasureIds);
+ }
+
+ private void insertComponent(String uuid, String projectUuid, String scope, String qualifier) {
+ db.executeInsert("PROJECTS",
+ "ORGANIZATION_UUID", "O1",
+ "KEE", "" + GENERATOR.incrementAndGet(),
+ "UUID", uuid,
+ "PROJECT_UUID", projectUuid,
+ "MAIN_BRANCH_PROJECT_UUID", "" + GENERATOR.incrementAndGet(),
+ "UUID_PATH", ".",
+ "ROOT_UUID", "" + GENERATOR.incrementAndGet(),
+ "PRIVATE", "true",
+ "QUALIFIER", qualifier,
+ "SCOPE", scope);
+ }
+
+ private void insertSnapshot(String uuid, String projectUuid, boolean last) {
+ db.executeInsert("SNAPSHOTS",
+ "UUID", uuid,
+ "COMPONENT_UUID", projectUuid,
+ "STATUS", "P",
+ "ISLAST", last);
+ }
+
+ private long insertMeasure(String componentUuid, String analysisUuid) {
+ long id = GENERATOR.incrementAndGet();
+ db.executeInsert("PROJECT_MEASURES",
+ "ID", id,
+ "METRIC_ID", "42",
+ "COMPONENT_UUID", componentUuid,
+ "ANALYSIS_UUID", analysisUuid);
+ return id;
+ }
+
+ private long insertPersonMeasure(String componentUuid, String analysisUuid) {
+ long id = GENERATOR.incrementAndGet();
+ db.executeInsert("PROJECT_MEASURES",
+ "ID", id,
+ "METRIC_ID", "42",
+ "COMPONENT_UUID", componentUuid,
+ "ANALYSIS_UUID", analysisUuid,
+ "PERSON_ID", RandomUtils.nextInt(100));
+ return id;
+ }
+}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2019 SonarSource SA
- * mailto:info 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.server.platform.db.migration.version.v70;
-
-import java.sql.SQLException;
-import java.util.concurrent.atomic.AtomicInteger;
-import org.apache.commons.lang.math.RandomUtils;
-import org.junit.Rule;
-import org.junit.Test;
-import org.sonar.api.config.internal.MapSettings;
-import org.sonar.db.CoreDbTester;
-import org.sonar.server.platform.db.migration.step.DataChange;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class DeletePersonAndFileMeasuresTest {
- private static final AtomicInteger GENERATOR = new AtomicInteger();
- @Rule
- public CoreDbTester db = CoreDbTester.createForSchema(DeletePersonAndFileMeasuresTest.class, "initial.sql");
-
- @Test
- public void delete_file_and_person_measures() throws SQLException {
- insertComponent("P1", "PRJ", "TRK");
- insertComponent("D1", "DIR", "DIR");
- insertComponent("F1", "FIL", "FIL");
- insertComponent("F2", "FIL", "UTS");
- insertSnapshot("S1", "P1", false);
- insertSnapshot("S2", "P1", true);
- // past measures
- long m1 = insertMeasure("P1", "S1");
- long m2 = insertMeasure("D1", "S1");
- long m3 = insertMeasure("F1", "S1");
- long m4 = insertMeasure("F2", "S1");
- long m5 = insertPersonMeasure("P1", "S1");
- long m6 = insertPersonMeasure("F1", "S1");
- // last measures
- long m7 = insertMeasure("P1", "S2");
- long m8 = insertMeasure("D1", "S2");
- long m9 = insertMeasure("F1", "S2");
- long m10 = insertMeasure("F2", "S2");
- long m11 = insertPersonMeasure("P1", "S2");
- long m12 = insertPersonMeasure("F1", "S2");
-
- run(false);
-
- assertThat(db.countRowsOfTable("PROJECTS")).isEqualTo(4);
- assertThat(db.countRowsOfTable("SNAPSHOTS")).isEqualTo(2);
- assertThatMeasuresAreExactly(m1, m2, m7, m8);
-
- // migration is re-entrant
- run(false);
- assertThat(db.countRowsOfTable("PROJECTS")).isEqualTo(4);
- assertThat(db.countRowsOfTable("SNAPSHOTS")).isEqualTo(2);
- assertThatMeasuresAreExactly(m1, m2, m7, m8);
- }
-
- @Test
- public void migration_is_disabled_on_sonarcloud() throws SQLException {
- insertComponent("F1", "FIL", "FIL");
- insertSnapshot("S1", "P1", false);
- insertMeasure("F1", "S1");
- insertPersonMeasure("F1", "S1");
-
- run(true);
-
- assertThat(db.countRowsOfTable("PROJECTS")).isEqualTo(1);
- assertThat(db.countRowsOfTable("SNAPSHOTS")).isEqualTo(1);
- assertThat(db.countRowsOfTable("PROJECT_MEASURES")).isEqualTo(2);
- }
-
- private void run(boolean sonarCloud) throws SQLException {
- MapSettings settings = new MapSettings();
- if (sonarCloud) {
- settings.setProperty("sonar.sonarcloud.enabled", true);
- }
- DataChange underTest = new DeletePersonAndFileMeasures(db.database(), settings.asConfig());
- underTest.execute();
- }
-
- private void assertThatMeasuresAreExactly(long... expectedMeasureIds) {
- long[] ids = db.select("select id as \"id\" from project_measures")
- .stream()
- .mapToLong(m -> (Long) m.get("id"))
- .toArray();
- assertThat(ids).containsOnly(expectedMeasureIds);
- }
-
- private void insertComponent(String uuid, String scope, String qualifier) {
- db.executeInsert("PROJECTS",
- "ORGANIZATION_UUID", "O1",
- "KEE", "" + GENERATOR.incrementAndGet(),
- "UUID", uuid,
- "PROJECT_UUID", "" + GENERATOR.incrementAndGet(),
- "MAIN_BRANCH_PROJECT_UUID", "" + GENERATOR.incrementAndGet(),
- "UUID_PATH", ".",
- "ROOT_UUID", "" + GENERATOR.incrementAndGet(),
- "PRIVATE", "true",
- "QUALIFIER", qualifier,
- "SCOPE", scope);
- }
-
- private void insertSnapshot(String uuid, String projectUuid, boolean last) {
- db.executeInsert("SNAPSHOTS",
- "UUID", uuid,
- "COMPONENT_UUID", projectUuid,
- "STATUS", "P",
- "ISLAST", last);
- }
-
- private long insertMeasure(String componentUuid, String analysisUuid) {
- long id = GENERATOR.incrementAndGet();
- db.executeInsert("PROJECT_MEASURES",
- "ID", id,
- "METRIC_ID", "42",
- "COMPONENT_UUID", componentUuid,
- "ANALYSIS_UUID", analysisUuid);
- return id;
- }
-
- private long insertPersonMeasure(String componentUuid, String analysisUuid) {
- long id = GENERATOR.incrementAndGet();
- db.executeInsert("PROJECT_MEASURES",
- "ID", id,
- "METRIC_ID", "42",
- "COMPONENT_UUID", componentUuid,
- "ANALYSIS_UUID", analysisUuid,
- "PERSON_ID", RandomUtils.nextInt(100));
- return id;
- }
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info 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.server.platform.db.migration.version.v70;
+
+import java.sql.SQLException;
+import java.util.concurrent.atomic.AtomicInteger;
+import org.apache.commons.lang.math.RandomUtils;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.db.CoreDbTester;
+import org.sonar.server.platform.db.migration.step.DataChange;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class DeletePersonMeasuresTest {
+ private static final AtomicInteger GENERATOR = new AtomicInteger();
+
+ @Rule
+ public CoreDbTester db = CoreDbTester.createForSchema(DeletePersonMeasuresTest.class, "initial.sql");
+
+ private DataChange underTest = new DeletePersonMeasures(db.database());
+
+ @Test
+ public void delete_person_measures() throws SQLException {
+ insertComponent("P1", "PRJ", "TRK");
+ insertComponent("D1", "DIR", "DIR");
+ insertComponent("F1", "FIL", "FIL");
+ insertComponent("F2", "FIL", "UTS");
+ insertSnapshot("S1", "P1", false);
+ insertSnapshot("S2", "P1", true);
+ // past measures
+ long m1 = insertMeasure("P1", "S1");
+ long m2 = insertMeasure("D1", "S1");
+ long m3 = insertMeasure("F1", "S1");
+ long m4 = insertMeasure("F2", "S1");
+ long m5 = insertPersonMeasure("P1", "S1");
+ long m6 = insertPersonMeasure("F1", "S1");
+ // last measures
+ long m7 = insertMeasure("P1", "S2");
+ long m8 = insertMeasure("D1", "S2");
+ long m9 = insertMeasure("F1", "S2");
+ long m10 = insertMeasure("F2", "S2");
+ long m11 = insertPersonMeasure("P1", "S2");
+ long m12 = insertPersonMeasure("F1", "S2");
+
+ underTest.execute();
+
+ assertThat(db.countRowsOfTable("PROJECTS")).isEqualTo(4);
+ assertThat(db.countRowsOfTable("SNAPSHOTS")).isEqualTo(2);
+ assertThatMeasuresAreExactly(m1, m2, m3, m4, m7, m8, m9, m10);
+
+ // migration is re-entrant
+ underTest.execute();
+ assertThat(db.countRowsOfTable("PROJECTS")).isEqualTo(4);
+ assertThat(db.countRowsOfTable("SNAPSHOTS")).isEqualTo(2);
+ assertThatMeasuresAreExactly(m1, m2, m3, m4, m7, m8, m9, m10);
+ }
+
+ private void assertThatMeasuresAreExactly(long... expectedMeasureIds) {
+ long[] ids = db.select("select id as \"id\" from project_measures")
+ .stream()
+ .mapToLong(m -> (Long) m.get("id"))
+ .toArray();
+ assertThat(ids).containsOnly(expectedMeasureIds);
+ }
+
+ private void insertComponent(String uuid, String scope, String qualifier) {
+ db.executeInsert("PROJECTS",
+ "ORGANIZATION_UUID", "O1",
+ "KEE", "" + GENERATOR.incrementAndGet(),
+ "UUID", uuid,
+ "PROJECT_UUID", "" + GENERATOR.incrementAndGet(),
+ "MAIN_BRANCH_PROJECT_UUID", "" + GENERATOR.incrementAndGet(),
+ "UUID_PATH", ".",
+ "ROOT_UUID", "" + GENERATOR.incrementAndGet(),
+ "PRIVATE", "true",
+ "QUALIFIER", qualifier,
+ "SCOPE", scope);
+ }
+
+ private void insertSnapshot(String uuid, String projectUuid, boolean last) {
+ db.executeInsert("SNAPSHOTS",
+ "UUID", uuid,
+ "COMPONENT_UUID", projectUuid,
+ "STATUS", "P",
+ "ISLAST", last);
+ }
+
+ private long insertMeasure(String componentUuid, String analysisUuid) {
+ long id = GENERATOR.incrementAndGet();
+ db.executeInsert("PROJECT_MEASURES",
+ "ID", id,
+ "METRIC_ID", "42",
+ "COMPONENT_UUID", componentUuid,
+ "ANALYSIS_UUID", analysisUuid);
+ return id;
+ }
+
+ private long insertPersonMeasure(String componentUuid, String analysisUuid) {
+ long id = GENERATOR.incrementAndGet();
+ db.executeInsert("PROJECT_MEASURES",
+ "ID", id,
+ "METRIC_ID", "42",
+ "COMPONENT_UUID", componentUuid,
+ "ANALYSIS_UUID", analysisUuid,
+ "PERSON_ID", RandomUtils.nextInt(100));
+ return id;
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info 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.server.platform.db.migration.version.v70;
+
+import java.sql.SQLException;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.db.CoreDbTester;
+
+public class DropSnapshotIsLastIndexTest {
+
+ @Rule
+ public CoreDbTester db = CoreDbTester.createForSchema(DropSnapshotIsLastIndexTest.class, "snapshots.sql");
+
+ private DropSnapshotIsLastIndex underTest = new DropSnapshotIsLastIndex(db.database());
+
+ @Test
+ public void drop_index_on_snapshots_islast() throws SQLException {
+ underTest.execute();
+
+ db.assertIndexDoesNotExist("snapshots", "ix_snapshot_is_last");
+ }
+
+ @Test
+ public void migration_is_reentrant() throws SQLException {
+ underTest.execute();
+
+ underTest.execute();
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 SonarSource SA
+ * mailto:info 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.server.platform.db.migration.version.v70;
+
+import java.sql.SQLException;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.db.CoreDbTester;
+
+public class DropTempTableLiveMeasuresPTest {
+
+ @Rule
+ public CoreDbTester db = CoreDbTester.createForSchema(DropTempTableLiveMeasuresPTest.class, "live_measures_p.sql");
+
+ private DropTempTableLiveMeasuresP underTest = new DropTempTableLiveMeasuresP(db.database());
+
+ @Test
+ public void drop_table_live_measures_p() throws SQLException {
+ String tableName = "live_measures_p";
+
+ db.assertTableExists(tableName);
+
+ underTest.execute();
+
+ db.assertTableDoesNotExist(tableName);
+ }
+
+ @Test
+ public void migration_is_reentrant() throws SQLException {
+ underTest.execute();
+
+ underTest.execute();
+ }
+}
package org.sonar.server.platform.db.migration.version.v70;
import java.sql.SQLException;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
field("VALUE"),
field("TEXT_VALUE"),
field("VARIATION"),
- field("MEASURE_DATA")
- ).containsExactlyInAnyOrder(generateLiveMeasures());
- }
+ field("MEASURE_DATA")).containsExactlyInAnyOrder(generateLiveMeasures());
- private Function<Map<String, Object>, Object> field(String name) {
- return m -> m.get(name);
+ assertThat(db.select("select project_uuid as \"PROJECT_UUID\" from live_measures_p"))
+ .extracting(t -> t.get("PROJECT_UUID"))
+ .containsOnly("PRJ1", "PRJ2");
}
@Test
field("VALUE"),
field("TEXT_VALUE"),
field("VARIATION"),
- field("MEASURE_DATA")
- ).containsExactlyInAnyOrder(generateLiveMeasures());
+ field("MEASURE_DATA")).containsExactlyInAnyOrder(generateLiveMeasures());
+ }
+
+ @Test
+ public void do_not_fail_if_live_measure_of_component_already_partially_inserted() throws SQLException {
+ generateProjectMeasures();
+
+ db.executeInsert(
+ "LIVE_MEASURES",
+ "UUID", "foo",
+ "COMPONENT_UUID", "PRJ1",
+ "PROJECT_UUID", "PRJ1",
+ "METRIC_ID", 1010,
+ "CREATED_AT", 1L,
+ "UPDATED_AT", 1L
+ );
+
+ underTest.execute();
+
+ }
+
+ private Function<Map<String, Object>, Object> field(String name) {
+ return m -> m.get(name);
}
private void generateProjectMeasures() {
- Map<String, Object> project = new HashMap<>();
- project.put("UUID", "PRJ1");
- project.put("ORGANIZATION_UUID", "ORG1");
- project.put("UUID_PATH", "X");
- project.put("ROOT_UUID", "X");
- project.put("PROJECT_UUID", "PRJ1");
- project.put("PRIVATE", "FALSE");
- db.executeInsert("PROJECTS", project);
-
- Map<String, Object> analysis1 = new HashMap<>();
- analysis1.put("UUID", "A1");
- analysis1.put("ISLAST", "FALSE");
- analysis1.put("COMPONENT_UUID", "PRJ1");
- db.executeInsert("SNAPSHOTS", analysis1);
-
- Map<String, Object> analysis2 = new HashMap<>();
- analysis2.put("UUID", "A2");
- analysis2.put("ISLAST", "TRUE");
- analysis2.put("COMPONENT_UUID", "PRJ1");
- db.executeInsert("SNAPSHOTS", analysis2);
-
- Map<String, Object> measure1 = new HashMap<>();
- measure1.put("COMPONENT_UUID", "PRJ1");
- measure1.put("ANALYSIS_UUID", "A1");
- measure1.put("METRIC_ID", "123");
- db.executeInsert("PROJECT_MEASURES", measure1);
-
- Map<String, Object> measure2 = new HashMap<>();
- measure2.put("COMPONENT_UUID", "PRJ1");
- measure2.put("ANALYSIS_UUID", "A2");
- measure2.put("METRIC_ID", "123");
- measure2.put("VALUE", "234");
- measure2.put("TEXT_VALUE", "TEXT_VALUEx");
- measure2.put("VARIATION_VALUE_1", "345");
- measure2.put("MEASURE_DATA", "FFFF");
- db.executeInsert("PROJECT_MEASURES", measure2);
-
- // measures with person_id not null are purged later
- // by another migration
- Map<String, Object> personMeasure = new HashMap<>();
- personMeasure.put("COMPONENT_UUID", "PRJ1");
- personMeasure.put("ANALYSIS_UUID", "A2");
- personMeasure.put("METRIC_ID", "200");
- personMeasure.put("VALUE", "234");
- personMeasure.put("TEXT_VALUE", "TEXT_VALUEx");
- personMeasure.put("VARIATION_VALUE_1", "345");
- personMeasure.put("MEASURE_DATA", "FFFF");
- personMeasure.put("PERSON_ID", "99");
- db.executeInsert("PROJECT_MEASURES", personMeasure);
+ db.executeInsert("PROJECTS",
+ "UUID", "PRJ1",
+ "PROJECT_UUID", "PRJ1",
+ "ORGANIZATION_UUID", "ORG1",
+ "UUID_PATH", "X",
+ "ROOT_UUID", "X",
+ "PRIVATE", "FALSE");
+ db.executeInsert("PROJECTS",
+ "UUID", "DIR1",
+ "PROJECT_UUID", "PRJ1",
+ "ORGANIZATION_UUID", "ORG1",
+ "UUID_PATH", "X",
+ "ROOT_UUID", "X",
+ "PRIVATE", "FALSE");
+ db.executeInsert("PROJECTS",
+ "UUID", "FIL1",
+ "PROJECT_UUID", "PRJ1",
+ "ORGANIZATION_UUID", "ORG1",
+ "UUID_PATH", "X",
+ "ROOT_UUID", "X",
+ "PRIVATE", "FALSE");
+ db.executeInsert("PROJECTS",
+ "UUID", "PRJ2",
+ "PROJECT_UUID", "PRJ2",
+ "ORGANIZATION_UUID", "ORG1",
+ "UUID_PATH", "X",
+ "ROOT_UUID", "X",
+ "PRIVATE", "FALSE");
+ db.executeInsert("PROJECTS",
+ "UUID", "DIR2",
+ "PROJECT_UUID", "PRJ2",
+ "ORGANIZATION_UUID", "ORG1",
+ "UUID_PATH", "X",
+ "ROOT_UUID", "X",
+ "PRIVATE", "FALSE");
+ db.executeInsert("PROJECTS",
+ "UUID", "FIL2",
+ "PROJECT_UUID", "PRJ2",
+ "ORGANIZATION_UUID", "ORG1",
+ "UUID_PATH", "X",
+ "ROOT_UUID", "X",
+ "PRIVATE", "FALSE");
+ db.executeInsert("PROJECTS",
+ "UUID", "PRJ3",
+ "PROJECT_UUID", "PRJ3",
+ "ORGANIZATION_UUID", "ORG1",
+ "UUID_PATH", "X",
+ "ROOT_UUID", "X",
+ "PRIVATE", "FALSE");
+ db.executeInsert("PROJECTS",
+ "UUID", "PRJ4",
+ "PROJECT_UUID", "PRJ4",
+ "ORGANIZATION_UUID", "ORG1",
+ "UUID_PATH", "X",
+ "ROOT_UUID", "X",
+ "PRIVATE", "FALSE");
+
+ // non last snapshot, none of its measures should be copied to live_measures
+ db.executeInsert("SNAPSHOTS",
+ "UUID", "1A1",
+ "ISLAST", "FALSE",
+ "COMPONENT_UUID", "PRJ1");
+ db.executeInsert("PROJECT_MEASURES",
+ "COMPONENT_UUID", "PRJ1",
+ "ANALYSIS_UUID", "1A1",
+ "METRIC_ID", "100");
+ db.executeInsert("PROJECT_MEASURES",
+ "COMPONENT_UUID", "DIR1",
+ "ANALYSIS_UUID", "1A1",
+ "METRIC_ID", "110",
+ "VALUE", "11");
+ db.executeInsert("PROJECT_MEASURES",
+ "COMPONENT_UUID", "FIL1",
+ "ANALYSIS_UUID", "1A1",
+ "METRIC_ID", "120",
+ "VALUE", "12");
+ db.executeInsert("SNAPSHOTS",
+ "UUID", "1A2",
+ "ISLAST", "FALSE",
+ "COMPONENT_UUID", "PRJ2");
+ db.executeInsert("PROJECT_MEASURES",
+ "COMPONENT_UUID", "PRJ2",
+ "ANALYSIS_UUID", "1A2",
+ "METRIC_ID", "200");
+ db.executeInsert("PROJECT_MEASURES",
+ "COMPONENT_UUID", "DIR2",
+ "ANALYSIS_UUID", "1A2",
+ "METRIC_ID", "210",
+ "VALUE", "21");
+ db.executeInsert("PROJECT_MEASURES",
+ "COMPONENT_UUID", "FIL2",
+ "ANALYSIS_UUID", "1A2",
+ "METRIC_ID", "220",
+ "VALUE", "22");
+ // PRJ3 has only non-last snapshot??!!?? => won't go into live_measures_p
+ db.executeInsert("SNAPSHOTS",
+ "UUID", "1A3",
+ "ISLAST", "FALSE",
+ "COMPONENT_UUID", "PRJ3");
+
+ // last snapshot, all measure should be copied to live_measures
+ db.executeInsert("SNAPSHOTS",
+ "UUID", "2A1",
+ "ISLAST", "TRUE",
+ "COMPONENT_UUID", "PRJ1");
+ db.executeInsert("PROJECT_MEASURES",
+ "COMPONENT_UUID", "PRJ1",
+ "ANALYSIS_UUID", "2A1",
+ "METRIC_ID", "1010",
+ "VALUE", "101",
+ "TEXT_VALUE", "TEXT_VALUEx",
+ "VARIATION_VALUE_1", "345",
+ "MEASURE_DATA", "FFFF");
+ db.executeInsert("PROJECT_MEASURES",
+ "COMPONENT_UUID", "PRJ1",
+ "ANALYSIS_UUID", "2A1",
+ "METRIC_ID", "1020",
+ "VALUE", "102");
+ db.executeInsert("PROJECT_MEASURES",
+ "COMPONENT_UUID", "DIR1",
+ "ANALYSIS_UUID", "2A1",
+ "METRIC_ID", "1030",
+ "VALUE", "103");
+ // FIL1 has no measure for this snapshot => will trigger infinite loop if not taken into account
+ db.executeInsert("SNAPSHOTS",
+ "UUID", "2A2",
+ "ISLAST", "TRUE",
+ "COMPONENT_UUID", "PRJ2");
+ db.executeInsert("PROJECT_MEASURES",
+ "COMPONENT_UUID", "PRJ2",
+ "ANALYSIS_UUID", "2A2",
+ "METRIC_ID", "2010",
+ "VALUE", "201",
+ "TEXT_VALUE", "TEXT_VALUEx",
+ "VARIATION_VALUE_1", "345",
+ "MEASURE_DATA", "FFFF");
+ db.executeInsert("PROJECT_MEASURES",
+ "COMPONENT_UUID", "PRJ2",
+ "ANALYSIS_UUID", "2A2",
+ "METRIC_ID", "2020",
+ "VALUE", "202");
+ db.executeInsert("PROJECT_MEASURES",
+ "COMPONENT_UUID", "DIR2",
+ "ANALYSIS_UUID", "2A2",
+ "METRIC_ID", "2030",
+ "VALUE", "203");
+ // FIL2 has no measure for this snapshot => will trigger infinite loop if not taken into account
+ // PRJ5 has last snapshot without measure => won't go into live_measures_p
+ db.executeInsert("SNAPSHOTS",
+ "UUID", "2A4",
+ "ISLAST", "FALSE",
+ "COMPONENT_UUID", "PRJ4");
}
private List<Map<String, Object>> getLiveMeasures() {
private Tuple[] generateLiveMeasures() {
return new Tuple[] {
- tuple("PRJ1", "PRJ1", 123L, 234.0, "TEXT_VALUEx", 345.0, new byte[] {-1, -1})
+ tuple("PRJ1", "PRJ1", 1010L, 101.0, "TEXT_VALUEx", 345.0, new byte[] {-1, -1}),
+ tuple("PRJ1", "PRJ1", 1020L, 102.0, null, null, null),
+ tuple("DIR1", "PRJ1", 1030L, 103.0, null, null, null),
+ tuple("PRJ2", "PRJ2", 2010L, 201.0, "TEXT_VALUEx", 345.0, new byte[] {-1, -1}),
+ tuple("PRJ2", "PRJ2", 2020L, 202.0, null, null, null),
+ tuple("DIR2", "PRJ2", 2030L, 203.0, null, null, null)
};
}
}
--- /dev/null
+CREATE TABLE "LIVE_MEASURES" (
+ "UUID" VARCHAR(40) NOT NULL PRIMARY KEY,
+ "PROJECT_UUID" VARCHAR(50) NOT NULL,
+ "COMPONENT_UUID" VARCHAR(50) NOT NULL,
+ "METRIC_ID" INTEGER NOT NULL,
+ "VALUE" DOUBLE,
+ "TEXT_VALUE" VARCHAR(4000),
+ "VARIATION" DOUBLE,
+ "MEASURE_DATA" BINARY,
+ "UPDATE_MARKER" VARCHAR(40),
+ "CREATED_AT" BIGINT NOT NULL,
+ "UPDATED_AT" BIGINT NOT NULL
+);
+CREATE INDEX "LIVE_MEASURES_PROJECT" ON "LIVE_MEASURES" ("PROJECT_UUID");
--- /dev/null
+CREATE TABLE "SNAPSHOTS" (
+ "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+ "UUID" VARCHAR(50) NOT NULL,
+ "CREATED_AT" BIGINT,
+ "BUILD_DATE" BIGINT,
+ "COMPONENT_UUID" VARCHAR(50) NOT NULL,
+ "STATUS" VARCHAR(4) NOT NULL DEFAULT 'U',
+ "PURGE_STATUS" INTEGER,
+ "ISLAST" BOOLEAN NOT NULL DEFAULT FALSE,
+ "VERSION" VARCHAR(500),
+ "PERIOD1_MODE" VARCHAR(100),
+ "PERIOD1_PARAM" VARCHAR(100),
+ "PERIOD1_DATE" BIGINT,
+ "PERIOD2_MODE" VARCHAR(100),
+ "PERIOD2_PARAM" VARCHAR(100),
+ "PERIOD2_DATE" BIGINT,
+ "PERIOD3_MODE" VARCHAR(100),
+ "PERIOD3_PARAM" VARCHAR(100),
+ "PERIOD3_DATE" BIGINT,
+ "PERIOD4_MODE" VARCHAR(100),
+ "PERIOD4_PARAM" VARCHAR(100),
+ "PERIOD4_DATE" BIGINT,
+ "PERIOD5_MODE" VARCHAR(100),
+ "PERIOD5_PARAM" VARCHAR(100),
+ "PERIOD5_DATE" BIGINT
+);
+CREATE INDEX "SNAPSHOT_COMPONENT" ON "SNAPSHOTS" ("COMPONENT_UUID");
+CREATE UNIQUE INDEX "ANALYSES_UUID" ON "SNAPSHOTS" ("UUID");
--- /dev/null
+CREATE TABLE "PROJECTS" (
+ "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+ "ORGANIZATION_UUID" VARCHAR(40) NOT NULL,
+ "KEE" VARCHAR(400),
+ "UUID" VARCHAR(50) NOT NULL,
+ "UUID_PATH" VARCHAR(1500) NOT NULL,
+ "ROOT_UUID" VARCHAR(50) NOT NULL,
+ "PROJECT_UUID" VARCHAR(50) NOT NULL,
+ "MODULE_UUID" VARCHAR(50),
+ "MODULE_UUID_PATH" VARCHAR(1500),
+ "MAIN_BRANCH_PROJECT_UUID" VARCHAR(50),
+ "NAME" VARCHAR(2000),
+ "DESCRIPTION" VARCHAR(2000),
+ "PRIVATE" BOOLEAN NOT NULL,
+ "TAGS" VARCHAR(500),
+ "ENABLED" BOOLEAN NOT NULL DEFAULT TRUE,
+ "SCOPE" VARCHAR(3),
+ "QUALIFIER" VARCHAR(10),
+ "DEPRECATED_KEE" VARCHAR(400),
+ "PATH" VARCHAR(2000),
+ "LANGUAGE" VARCHAR(20),
+ "COPY_COMPONENT_UUID" VARCHAR(50),
+ "LONG_NAME" VARCHAR(2000),
+ "DEVELOPER_UUID" VARCHAR(50),
+ "CREATED_AT" TIMESTAMP,
+ "AUTHORIZATION_UPDATED_AT" BIGINT,
+ "B_CHANGED" BOOLEAN,
+ "B_COPY_COMPONENT_UUID" VARCHAR(50),
+ "B_DESCRIPTION" VARCHAR(2000),
+ "B_ENABLED" BOOLEAN,
+ "B_UUID_PATH" VARCHAR(1500),
+ "B_LANGUAGE" VARCHAR(20),
+ "B_LONG_NAME" VARCHAR(500),
+ "B_MODULE_UUID" VARCHAR(50),
+ "B_MODULE_UUID_PATH" VARCHAR(1500),
+ "B_NAME" VARCHAR(500),
+ "B_PATH" VARCHAR(2000),
+ "B_QUALIFIER" VARCHAR(10)
+);
+CREATE INDEX "PROJECTS_ORGANIZATION" ON "PROJECTS" ("ORGANIZATION_UUID");
+CREATE UNIQUE INDEX "PROJECTS_KEE" ON "PROJECTS" ("KEE");
+CREATE INDEX "PROJECTS_ROOT_UUID" ON "PROJECTS" ("ROOT_UUID");
+CREATE UNIQUE INDEX "PROJECTS_UUID" ON "PROJECTS" ("UUID");
+CREATE INDEX "PROJECTS_PROJECT_UUID" ON "PROJECTS" ("PROJECT_UUID");
+CREATE INDEX "PROJECTS_MODULE_UUID" ON "PROJECTS" ("MODULE_UUID");
+CREATE INDEX "PROJECTS_QUALIFIER" ON "PROJECTS" ("QUALIFIER");
+
+
+CREATE TABLE "SNAPSHOTS" (
+ "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+ "UUID" VARCHAR(50) NOT NULL,
+ "CREATED_AT" BIGINT,
+ "BUILD_DATE" BIGINT,
+ "COMPONENT_UUID" VARCHAR(50) NOT NULL,
+ "STATUS" VARCHAR(4) NOT NULL DEFAULT 'U',
+ "PURGE_STATUS" INTEGER,
+ "ISLAST" BOOLEAN NOT NULL DEFAULT FALSE,
+ "VERSION" VARCHAR(500),
+ "PERIOD1_MODE" VARCHAR(100),
+ "PERIOD1_PARAM" VARCHAR(100),
+ "PERIOD1_DATE" BIGINT,
+ "PERIOD2_MODE" VARCHAR(100),
+ "PERIOD2_PARAM" VARCHAR(100),
+ "PERIOD2_DATE" BIGINT,
+ "PERIOD3_MODE" VARCHAR(100),
+ "PERIOD3_PARAM" VARCHAR(100),
+ "PERIOD3_DATE" BIGINT,
+ "PERIOD4_MODE" VARCHAR(100),
+ "PERIOD4_PARAM" VARCHAR(100),
+ "PERIOD4_DATE" BIGINT,
+ "PERIOD5_MODE" VARCHAR(100),
+ "PERIOD5_PARAM" VARCHAR(100),
+ "PERIOD5_DATE" BIGINT
+);
+CREATE INDEX "SNAPSHOT_COMPONENT" ON "SNAPSHOTS" ("COMPONENT_UUID");
+CREATE UNIQUE INDEX "ANALYSES_UUID" ON "SNAPSHOTS" ("UUID");
+
+
+CREATE TABLE "PROJECT_MEASURES" (
+ "ID" BIGINT NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+ "VALUE" DOUBLE,
+ "METRIC_ID" INTEGER NOT NULL,
+ "COMPONENT_UUID" VARCHAR(50) NOT NULL,
+ "ANALYSIS_UUID" VARCHAR(50) NOT NULL,
+ "TEXT_VALUE" VARCHAR(4000),
+ "ALERT_STATUS" VARCHAR(5),
+ "ALERT_TEXT" VARCHAR(4000),
+ "DESCRIPTION" VARCHAR(4000),
+ "PERSON_ID" INTEGER,
+ "VARIATION_VALUE_1" DOUBLE,
+ "VARIATION_VALUE_2" DOUBLE,
+ "VARIATION_VALUE_3" DOUBLE,
+ "VARIATION_VALUE_4" DOUBLE,
+ "VARIATION_VALUE_5" DOUBLE,
+ "MEASURE_DATA" BINARY
+);
+CREATE INDEX "MEASURES_COMPONENT_UUID" ON "PROJECT_MEASURES" ("COMPONENT_UUID");
+CREATE INDEX "MEASURES_ANALYSIS_METRIC" ON "PROJECT_MEASURES" ("ANALYSIS_UUID", "METRIC_ID");
--- /dev/null
+CREATE TABLE "PROJECTS" (
+ "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+ "ORGANIZATION_UUID" VARCHAR(40) NOT NULL,
+ "KEE" VARCHAR(400),
+ "UUID" VARCHAR(50) NOT NULL,
+ "UUID_PATH" VARCHAR(1500) NOT NULL,
+ "ROOT_UUID" VARCHAR(50) NOT NULL,
+ "PROJECT_UUID" VARCHAR(50) NOT NULL,
+ "MODULE_UUID" VARCHAR(50),
+ "MODULE_UUID_PATH" VARCHAR(1500),
+ "MAIN_BRANCH_PROJECT_UUID" VARCHAR(50),
+ "NAME" VARCHAR(2000),
+ "DESCRIPTION" VARCHAR(2000),
+ "PRIVATE" BOOLEAN NOT NULL,
+ "TAGS" VARCHAR(500),
+ "ENABLED" BOOLEAN NOT NULL DEFAULT TRUE,
+ "SCOPE" VARCHAR(3),
+ "QUALIFIER" VARCHAR(10),
+ "DEPRECATED_KEE" VARCHAR(400),
+ "PATH" VARCHAR(2000),
+ "LANGUAGE" VARCHAR(20),
+ "COPY_COMPONENT_UUID" VARCHAR(50),
+ "LONG_NAME" VARCHAR(2000),
+ "DEVELOPER_UUID" VARCHAR(50),
+ "CREATED_AT" TIMESTAMP,
+ "AUTHORIZATION_UPDATED_AT" BIGINT,
+ "B_CHANGED" BOOLEAN,
+ "B_COPY_COMPONENT_UUID" VARCHAR(50),
+ "B_DESCRIPTION" VARCHAR(2000),
+ "B_ENABLED" BOOLEAN,
+ "B_UUID_PATH" VARCHAR(1500),
+ "B_LANGUAGE" VARCHAR(20),
+ "B_LONG_NAME" VARCHAR(500),
+ "B_MODULE_UUID" VARCHAR(50),
+ "B_MODULE_UUID_PATH" VARCHAR(1500),
+ "B_NAME" VARCHAR(500),
+ "B_PATH" VARCHAR(2000),
+ "B_QUALIFIER" VARCHAR(10)
+);
+CREATE INDEX "PROJECTS_ORGANIZATION" ON "PROJECTS" ("ORGANIZATION_UUID");
+CREATE UNIQUE INDEX "PROJECTS_KEE" ON "PROJECTS" ("KEE");
+CREATE INDEX "PROJECTS_ROOT_UUID" ON "PROJECTS" ("ROOT_UUID");
+CREATE UNIQUE INDEX "PROJECTS_UUID" ON "PROJECTS" ("UUID");
+CREATE INDEX "PROJECTS_PROJECT_UUID" ON "PROJECTS" ("PROJECT_UUID");
+CREATE INDEX "PROJECTS_MODULE_UUID" ON "PROJECTS" ("MODULE_UUID");
+CREATE INDEX "PROJECTS_QUALIFIER" ON "PROJECTS" ("QUALIFIER");
+
+
+CREATE TABLE "SNAPSHOTS" (
+ "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+ "UUID" VARCHAR(50) NOT NULL,
+ "CREATED_AT" BIGINT,
+ "BUILD_DATE" BIGINT,
+ "COMPONENT_UUID" VARCHAR(50) NOT NULL,
+ "STATUS" VARCHAR(4) NOT NULL DEFAULT 'U',
+ "PURGE_STATUS" INTEGER,
+ "ISLAST" BOOLEAN NOT NULL DEFAULT FALSE,
+ "VERSION" VARCHAR(500),
+ "PERIOD1_MODE" VARCHAR(100),
+ "PERIOD1_PARAM" VARCHAR(100),
+ "PERIOD1_DATE" BIGINT,
+ "PERIOD2_MODE" VARCHAR(100),
+ "PERIOD2_PARAM" VARCHAR(100),
+ "PERIOD2_DATE" BIGINT,
+ "PERIOD3_MODE" VARCHAR(100),
+ "PERIOD3_PARAM" VARCHAR(100),
+ "PERIOD3_DATE" BIGINT,
+ "PERIOD4_MODE" VARCHAR(100),
+ "PERIOD4_PARAM" VARCHAR(100),
+ "PERIOD4_DATE" BIGINT,
+ "PERIOD5_MODE" VARCHAR(100),
+ "PERIOD5_PARAM" VARCHAR(100),
+ "PERIOD5_DATE" BIGINT
+);
+CREATE INDEX "SNAPSHOT_COMPONENT" ON "SNAPSHOTS" ("COMPONENT_UUID");
+CREATE UNIQUE INDEX "ANALYSES_UUID" ON "SNAPSHOTS" ("UUID");
+
+
+CREATE TABLE "PROJECT_MEASURES" (
+ "ID" BIGINT NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+ "VALUE" DOUBLE,
+ "METRIC_ID" INTEGER NOT NULL,
+ "COMPONENT_UUID" VARCHAR(50) NOT NULL,
+ "ANALYSIS_UUID" VARCHAR(50) NOT NULL,
+ "TEXT_VALUE" VARCHAR(4000),
+ "ALERT_STATUS" VARCHAR(5),
+ "ALERT_TEXT" VARCHAR(4000),
+ "DESCRIPTION" VARCHAR(4000),
+ "PERSON_ID" INTEGER,
+ "VARIATION_VALUE_1" DOUBLE,
+ "VARIATION_VALUE_2" DOUBLE,
+ "VARIATION_VALUE_3" DOUBLE,
+ "VARIATION_VALUE_4" DOUBLE,
+ "VARIATION_VALUE_5" DOUBLE,
+ "MEASURE_DATA" BINARY
+);
+CREATE INDEX "MEASURES_COMPONENT_UUID" ON "PROJECT_MEASURES" ("COMPONENT_UUID");
+CREATE INDEX "MEASURES_ANALYSIS_METRIC" ON "PROJECT_MEASURES" ("ANALYSIS_UUID", "METRIC_ID");
--- /dev/null
+CREATE TABLE "SNAPSHOTS" (
+ "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+ "UUID" VARCHAR(50) NOT NULL,
+ "CREATED_AT" BIGINT,
+ "BUILD_DATE" BIGINT,
+ "COMPONENT_UUID" VARCHAR(50) NOT NULL,
+ "STATUS" VARCHAR(4) NOT NULL DEFAULT 'U',
+ "PURGE_STATUS" INTEGER,
+ "ISLAST" BOOLEAN NOT NULL DEFAULT FALSE,
+ "VERSION" VARCHAR(500),
+ "PERIOD1_MODE" VARCHAR(100),
+ "PERIOD1_PARAM" VARCHAR(100),
+ "PERIOD1_DATE" BIGINT,
+ "PERIOD2_MODE" VARCHAR(100),
+ "PERIOD2_PARAM" VARCHAR(100),
+ "PERIOD2_DATE" BIGINT,
+ "PERIOD3_MODE" VARCHAR(100),
+ "PERIOD3_PARAM" VARCHAR(100),
+ "PERIOD3_DATE" BIGINT,
+ "PERIOD4_MODE" VARCHAR(100),
+ "PERIOD4_PARAM" VARCHAR(100),
+ "PERIOD4_DATE" BIGINT,
+ "PERIOD5_MODE" VARCHAR(100),
+ "PERIOD5_PARAM" VARCHAR(100),
+ "PERIOD5_DATE" BIGINT
+);
+CREATE INDEX "SNAPSHOT_COMPONENT" ON "SNAPSHOTS" ("COMPONENT_UUID");
+CREATE INDEX "IX_SNAPSHOT_IS_LAST" ON "SNAPSHOTS" ("ISLAST");
+CREATE UNIQUE INDEX "ANALYSES_UUID" ON "SNAPSHOTS" ("UUID");
--- /dev/null
+CREATE TABLE "LIVE_MEASURES_P" (
+ "PROJECT_UUID" VARCHAR(50) NOT NULL,
+ CONSTRAINT "PK_LIVE_MEASURES_P" PRIMARY KEY ("PROJECT_UUID")
+);
"PERIOD5_DATE" BIGINT
);
CREATE INDEX "SNAPSHOT_COMPONENT" ON "SNAPSHOTS" ("COMPONENT_UUID");
+-- temporary index added by previous DB migration
+CREATE INDEX "IX_SNAPSHOT_IS_LAST" ON "SNAPSHOTS" ("ISLAST");
CREATE UNIQUE INDEX "ANALYSES_UUID" ON "SNAPSHOTS" ("UUID");
"UPDATED_AT" BIGINT NOT NULL
);
CREATE INDEX "LIVE_MEASURES_PROJECT" ON "LIVE_MEASURES" ("PROJECT_UUID");
-CREATE UNIQUE INDEX "LIVE_MEASURES_COMPONENT" ON "LIVE_MEASURES" ("COMPONENT_UUID", "METRIC_ID");
+
+-- temporary table created by previous DB migration
+CREATE TABLE "LIVE_MEASURES_P" (
+ "PROJECT_UUID" VARCHAR(50) NOT NULL,
+ CONSTRAINT "PK_LIVE_MEASURES_P" PRIMARY KEY ("PROJECT_UUID")
+);
CREATE TABLE "PROJECT_MEASURES" (
"MEASURE_DATA" BINARY
);
CREATE INDEX "MEASURES_COMPONENT_UUID" ON "PROJECT_MEASURES" ("COMPONENT_UUID");
-CREATE INDEX "MEASURES_ANALYSIS_METRIC" ON "PROJECT_MEASURES" ("ANALYSIS_UUID", "METRIC_ID");
-CREATE INDEX "MEASURES_PERSON" ON "PROJECT_MEASURES" ("PERSON_ID");