aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorSébastien Lesaint <sebastien.lesaint@sonarsource.com>2019-06-26 15:56:09 +0200
committerSonarTech <sonartech@sonarsource.com>2019-06-28 20:21:12 +0200
commit515876435fd5a935147ea0e52b26ac798c269541 (patch)
treee67e04b6a84c5da4e8a1e43220d1fc48623d1509 /server
parent98d70ead6633d2614890c83fe36709485d149ecd (diff)
downloadsonarqube-515876435fd5a935147ea0e52b26ac798c269541.tar.gz
sonarqube-515876435fd5a935147ea0e52b26ac798c269541.zip
SONAR-12127 optimize migrations on LIVE_MEASURES and PROJECT_MEASURES
Diffstat (limited to 'server')
-rw-r--r--server/sonar-db-core/src/main/java/org/sonar/db/DatabaseUtils.java50
-rw-r--r--server/sonar-db-core/src/test/java/org/sonar/db/AbstractDbTester.java10
-rw-r--r--server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/sql/DropIndexBuilder.java11
-rw-r--r--server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/step/DataChange.java2
-rw-r--r--server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/AddLiveMeasuresMetricIndex.java59
-rw-r--r--server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/AddSnapshotIsLastIndex.java47
-rw-r--r--server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/CreateTableLiveMeasures.java36
-rw-r--r--server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/CreateTempTableLiveMeasuresP.java52
-rw-r--r--server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/DbVersion70.java57
-rw-r--r--server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/DeleteFileMeasures.java48
-rw-r--r--server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/DeletePersonMeasures.java (renamed from server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/DeletePersonAndFileMeasures.java)21
-rw-r--r--server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/DropSnapshotIsLastIndex.java40
-rw-r--r--server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/DropTempTableLiveMeasuresP.java40
-rw-r--r--server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/PopulateLiveMeasures.java196
-rw-r--r--server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/MigrationConfigurationModuleTest.java2
-rw-r--r--server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/history/NoTableMigrationHistoryImplTest.java9
-rw-r--r--server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/AddLiveMeasuresMetricIndexTest.java45
-rw-r--r--server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/AddSnapshotIsLastIndexTest.java52
-rw-r--r--server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/CreateTableLiveMeasuresTest.java1
-rw-r--r--server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/CreateTempTableLiveMeasuresPTest.java52
-rw-r--r--server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/DbVersion70Test.java4
-rw-r--r--server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/DeleteFileMeasuresTest.java127
-rw-r--r--server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/DeletePersonMeasuresTest.java (renamed from server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/DeletePersonAndFileMeasuresTest.java)41
-rw-r--r--server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/DropSnapshotIsLastIndexTest.java47
-rw-r--r--server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/DropTempTableLiveMeasuresPTest.java51
-rw-r--r--server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/PopulateLiveMeasuresTest.java243
-rw-r--r--server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v70/AddLiveMeasuresMetricIndexTest/live_measures.sql14
-rw-r--r--server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v70/AddSnapshotIsLastIndexTest/snapshots.sql28
-rw-r--r--server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v70/CreateTempTableLiveMeasuresPTest/empty.sql0
-rw-r--r--server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v70/DeleteFileMeasuresTest/initial.sql98
-rw-r--r--server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v70/DeletePersonMeasuresTest/initial.sql98
-rw-r--r--server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v70/DropSnapshotIsLastIndexTest/snapshots.sql29
-rw-r--r--server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v70/DropTempTableLiveMeasuresPTest/live_measures_p.sql4
-rw-r--r--server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v70/PopulateLiveMeasuresTest/initial.sql11
34 files changed, 1433 insertions, 192 deletions
diff --git a/server/sonar-db-core/src/main/java/org/sonar/db/DatabaseUtils.java b/server/sonar-db-core/src/main/java/org/sonar/db/DatabaseUtils.java
index cc6a884b9b7..cd2a7d3a429 100644
--- a/server/sonar-db-core/src/main/java/org/sonar/db/DatabaseUtils.java
+++ b/server/sonar-db-core/src/main/java/org/sonar/db/DatabaseUtils.java
@@ -294,17 +294,7 @@ public class DatabaseUtils {
}
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)) {
@@ -320,6 +310,44 @@ public class DatabaseUtils {
}
}
+ 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);
}
diff --git a/server/sonar-db-core/src/test/java/org/sonar/db/AbstractDbTester.java b/server/sonar-db-core/src/test/java/org/sonar/db/AbstractDbTester.java
index 3ea4852ccf5..23ae8e7dd32 100644
--- a/server/sonar-db-core/src/test/java/org/sonar/db/AbstractDbTester.java
+++ b/server/sonar-db-core/src/test/java/org/sonar/db/AbstractDbTester.java
@@ -405,9 +405,17 @@ public class AbstractDbTester<T extends CoreTestDb> extends ExternalResource {
}
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);
}
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/sql/DropIndexBuilder.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/sql/DropIndexBuilder.java
index 1828e4465d4..548cbfbf87c 100644
--- a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/sql/DropIndexBuilder.java
+++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/sql/DropIndexBuilder.java
@@ -19,7 +19,11 @@
*/
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;
@@ -72,4 +76,11 @@ public class DropIndexBuilder {
}
}
+ public boolean indexExists(Database database) throws SQLException {
+ validateTableName(tableName);
+ validateIndexName(indexName);
+ try (Connection connection = database.getDataSource().getConnection()) {
+ return DatabaseUtils.indexExists(tableName, indexName, connection);
+ }
+ }
}
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/step/DataChange.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/step/DataChange.java
index e580d473816..a6beab641fc 100644
--- a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/step/DataChange.java
+++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/step/DataChange.java
@@ -48,7 +48,7 @@ public abstract class DataChange implements MigrationStep {
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)) {
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/AddLiveMeasuresMetricIndex.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/AddLiveMeasuresMetricIndex.java
new file mode 100644
index 00000000000..d08933471a4
--- /dev/null
+++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/AddLiveMeasuresMetricIndex.java
@@ -0,0 +1,59 @@
+/*
+ * 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());
+ }
+}
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/AddSnapshotIsLastIndex.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/AddSnapshotIsLastIndex.java
new file mode 100644
index 00000000000..0f555576f04
--- /dev/null
+++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/AddSnapshotIsLastIndex.java
@@ -0,0 +1,47 @@
+/*
+ * 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());
+ }
+}
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/CreateTableLiveMeasures.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/CreateTableLiveMeasures.java
index ad4a5ed97d4..a86d9d78e8f 100644
--- a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/CreateTableLiveMeasures.java
+++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/CreateTableLiveMeasures.java
@@ -31,6 +31,7 @@ import static org.sonar.server.platform.db.migration.def.BlobColumnDef.newBlobCo
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 {
@@ -43,21 +44,23 @@ 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")
@@ -97,29 +100,10 @@ public class CreateTableLiveMeasures extends DdlChange {
.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());
}
}
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/CreateTempTableLiveMeasuresP.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/CreateTempTableLiveMeasuresP.java
new file mode 100644
index 00000000000..faf4bb4fe12
--- /dev/null
+++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/CreateTempTableLiveMeasuresP.java
@@ -0,0 +1,52 @@
+/*
+ * 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());
+ }
+ }
+}
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/DbVersion70.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/DbVersion70.java
index 1f7757a4519..7f080c3243d 100644
--- a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/DbVersion70.java
+++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/DbVersion70.java
@@ -27,30 +27,39 @@ public class DbVersion70 implements DbVersion {
@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)
;
}
}
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/DeleteFileMeasures.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/DeleteFileMeasures.java
new file mode 100644
index 00000000000..58861ab22e6
--- /dev/null
+++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/DeleteFileMeasures.java
@@ -0,0 +1,48 @@
+/*
+ * 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;
+ });
+ }
+
+}
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/DeletePersonAndFileMeasures.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/DeletePersonMeasures.java
index 2a942e21771..1f78dc960c1 100644
--- a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/DeletePersonAndFileMeasures.java
+++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/DeletePersonMeasures.java
@@ -20,7 +20,6 @@
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;
@@ -30,22 +29,14 @@ 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 {
+public class DeletePersonMeasures extends DataChange {
- private final Configuration configuration;
-
- public DeletePersonAndFileMeasures(Database db, Configuration configuration) {
+ public DeletePersonMeasures(Database db) {
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");
@@ -68,27 +59,27 @@ public class DeletePersonAndFileMeasures extends DataChange {
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)";
+ "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 (c.qualifier in ('UTS', 'FIL') or pm.person_id is not null) " +
+ " 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 (c.qualifier in ('UTS', 'FIL') or pm.person_id is not null) ";
+ "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 (c.qualifier in ('UTS', 'FIL') or pm.person_id is not null) " +
+ " and pm.person_id is not null " +
" and pm.id = pm2.id" +
") and pm.analysis_uuid = ?";
default:
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/DropSnapshotIsLastIndex.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/DropSnapshotIsLastIndex.java
new file mode 100644
index 00000000000..554a084cc5c
--- /dev/null
+++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/DropSnapshotIsLastIndex.java
@@ -0,0 +1,40 @@
+/*
+ * 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());
+ }
+}
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/DropTempTableLiveMeasuresP.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/DropTempTableLiveMeasuresP.java
new file mode 100644
index 00000000000..acec9071aae
--- /dev/null
+++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/DropTempTableLiveMeasuresP.java
@@ -0,0 +1,40 @@
+/*
+ * 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());
+ }
+ }
+}
diff --git a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/PopulateLiveMeasures.java b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/PopulateLiveMeasures.java
index 9115bba8ce0..2ad1464d4a1 100644
--- a/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/PopulateLiveMeasures.java
+++ b/server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v70/PopulateLiveMeasures.java
@@ -19,45 +19,165 @@
*/
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));
@@ -66,7 +186,51 @@ public class PopulateLiveMeasures extends DataChange {
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 + '\'' +
+ '}';
+ }
+ }
}
diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/MigrationConfigurationModuleTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/MigrationConfigurationModuleTest.java
index ec155560d80..5d7a4fa62dd 100644
--- a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/MigrationConfigurationModuleTest.java
+++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/MigrationConfigurationModuleTest.java
@@ -39,7 +39,7 @@ public class MigrationConfigurationModuleTest {
// DbVersion classes
+ 20
// Others
- + 3);
+ + 4);
}
}
diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/history/NoTableMigrationHistoryImplTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/history/NoTableMigrationHistoryImplTest.java
index 27aa42089a5..d47d2ba8c4f 100644
--- a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/history/NoTableMigrationHistoryImplTest.java
+++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/history/NoTableMigrationHistoryImplTest.java
@@ -19,19 +19,22 @@
*/
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() {
@@ -39,6 +42,8 @@ public class NoTableMigrationHistoryImplTest {
expectedException.expectMessage("Migration history table is missing");
underTest.start();
+
+ verifyZeroInteractions(migrationHistoryMeddler);
}
diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/AddLiveMeasuresMetricIndexTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/AddLiveMeasuresMetricIndexTest.java
new file mode 100644
index 00000000000..e4f697addad
--- /dev/null
+++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/AddLiveMeasuresMetricIndexTest.java
@@ -0,0 +1,45 @@
+/*
+ * 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");
+ }
+}
diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/AddSnapshotIsLastIndexTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/AddSnapshotIsLastIndexTest.java
new file mode 100644
index 00000000000..719ee1dee10
--- /dev/null
+++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/AddSnapshotIsLastIndexTest.java
@@ -0,0 +1,52 @@
+/*
+ * 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();
+ }
+}
diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/CreateTableLiveMeasuresTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/CreateTableLiveMeasuresTest.java
index 0272f61de1b..17865dfdd11 100644
--- a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/CreateTableLiveMeasuresTest.java
+++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/CreateTableLiveMeasuresTest.java
@@ -54,6 +54,5 @@ public class CreateTableLiveMeasuresTest {
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");
}
}
diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/CreateTempTableLiveMeasuresPTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/CreateTempTableLiveMeasuresPTest.java
new file mode 100644
index 00000000000..631888ee0a7
--- /dev/null
+++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/CreateTempTableLiveMeasuresPTest.java
@@ -0,0 +1,52 @@
+/*
+ * 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();
+ }
+}
diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/DbVersion70Test.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/DbVersion70Test.java
index 33776819931..c237a6c0b16 100644
--- a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/DbVersion70Test.java
+++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/DbVersion70Test.java
@@ -30,12 +30,12 @@ public class DbVersion70Test {
@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);
}
}
diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/DeleteFileMeasuresTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/DeleteFileMeasuresTest.java
new file mode 100644
index 00000000000..8befae37dc5
--- /dev/null
+++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/DeleteFileMeasuresTest.java
@@ -0,0 +1,127 @@
+/*
+ * 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;
+ }
+}
diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/DeletePersonAndFileMeasuresTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/DeletePersonMeasuresTest.java
index a6188242b4c..e0d21418e16 100644
--- a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/DeletePersonAndFileMeasuresTest.java
+++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/DeletePersonMeasuresTest.java
@@ -24,19 +24,21 @@ 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 {
+public class DeletePersonMeasuresTest {
private static final AtomicInteger GENERATOR = new AtomicInteger();
+
@Rule
- public CoreDbTester db = CoreDbTester.createForSchema(DeletePersonAndFileMeasuresTest.class, "initial.sql");
+ public CoreDbTester db = CoreDbTester.createForSchema(DeletePersonMeasuresTest.class, "initial.sql");
+
+ private DataChange underTest = new DeletePersonMeasures(db.database());
@Test
- public void delete_file_and_person_measures() throws SQLException {
+ public void delete_person_measures() throws SQLException {
insertComponent("P1", "PRJ", "TRK");
insertComponent("D1", "DIR", "DIR");
insertComponent("F1", "FIL", "FIL");
@@ -58,40 +60,17 @@ public class DeletePersonAndFileMeasuresTest {
long m11 = insertPersonMeasure("P1", "S2");
long m12 = insertPersonMeasure("F1", "S2");
- run(false);
+ underTest.execute();
assertThat(db.countRowsOfTable("PROJECTS")).isEqualTo(4);
assertThat(db.countRowsOfTable("SNAPSHOTS")).isEqualTo(2);
- assertThatMeasuresAreExactly(m1, m2, m7, m8);
+ assertThatMeasuresAreExactly(m1, m2, m3, m4, m7, m8, m9, m10);
// migration is re-entrant
- run(false);
+ underTest.execute();
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();
+ assertThatMeasuresAreExactly(m1, m2, m3, m4, m7, m8, m9, m10);
}
private void assertThatMeasuresAreExactly(long... expectedMeasureIds) {
diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/DropSnapshotIsLastIndexTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/DropSnapshotIsLastIndexTest.java
new file mode 100644
index 00000000000..536f34872ef
--- /dev/null
+++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/DropSnapshotIsLastIndexTest.java
@@ -0,0 +1,47 @@
+/*
+ * 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();
+ }
+}
diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/DropTempTableLiveMeasuresPTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/DropTempTableLiveMeasuresPTest.java
new file mode 100644
index 00000000000..5a160e591bd
--- /dev/null
+++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/DropTempTableLiveMeasuresPTest.java
@@ -0,0 +1,51 @@
+/*
+ * 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();
+ }
+}
diff --git a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/PopulateLiveMeasuresTest.java b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/PopulateLiveMeasuresTest.java
index 10bd9221d05..f125ad3f0fb 100644
--- a/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/PopulateLiveMeasuresTest.java
+++ b/server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v70/PopulateLiveMeasuresTest.java
@@ -20,7 +20,6 @@
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;
@@ -63,12 +62,11 @@ public class PopulateLiveMeasuresTest {
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
@@ -85,60 +83,184 @@ public class PopulateLiveMeasuresTest {
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() {
@@ -147,7 +269,12 @@ public class PopulateLiveMeasuresTest {
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)
};
}
}
diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v70/AddLiveMeasuresMetricIndexTest/live_measures.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v70/AddLiveMeasuresMetricIndexTest/live_measures.sql
new file mode 100644
index 00000000000..291df9899c4
--- /dev/null
+++ b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v70/AddLiveMeasuresMetricIndexTest/live_measures.sql
@@ -0,0 +1,14 @@
+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");
diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v70/AddSnapshotIsLastIndexTest/snapshots.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v70/AddSnapshotIsLastIndexTest/snapshots.sql
new file mode 100644
index 00000000000..7d8f2963a86
--- /dev/null
+++ b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v70/AddSnapshotIsLastIndexTest/snapshots.sql
@@ -0,0 +1,28 @@
+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");
diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v70/CreateTempTableLiveMeasuresPTest/empty.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v70/CreateTempTableLiveMeasuresPTest/empty.sql
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v70/CreateTempTableLiveMeasuresPTest/empty.sql
diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v70/DeleteFileMeasuresTest/initial.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v70/DeleteFileMeasuresTest/initial.sql
new file mode 100644
index 00000000000..be55d6f14e8
--- /dev/null
+++ b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v70/DeleteFileMeasuresTest/initial.sql
@@ -0,0 +1,98 @@
+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");
diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v70/DeletePersonMeasuresTest/initial.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v70/DeletePersonMeasuresTest/initial.sql
new file mode 100644
index 00000000000..be55d6f14e8
--- /dev/null
+++ b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v70/DeletePersonMeasuresTest/initial.sql
@@ -0,0 +1,98 @@
+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");
diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v70/DropSnapshotIsLastIndexTest/snapshots.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v70/DropSnapshotIsLastIndexTest/snapshots.sql
new file mode 100644
index 00000000000..53bee7b6bce
--- /dev/null
+++ b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v70/DropSnapshotIsLastIndexTest/snapshots.sql
@@ -0,0 +1,29 @@
+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");
diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v70/DropTempTableLiveMeasuresPTest/live_measures_p.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v70/DropTempTableLiveMeasuresPTest/live_measures_p.sql
new file mode 100644
index 00000000000..0632f993b4e
--- /dev/null
+++ b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v70/DropTempTableLiveMeasuresPTest/live_measures_p.sql
@@ -0,0 +1,4 @@
+CREATE TABLE "LIVE_MEASURES_P" (
+ "PROJECT_UUID" VARCHAR(50) NOT NULL,
+ CONSTRAINT "PK_LIVE_MEASURES_P" PRIMARY KEY ("PROJECT_UUID")
+);
diff --git a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v70/PopulateLiveMeasuresTest/initial.sql b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v70/PopulateLiveMeasuresTest/initial.sql
index b3dc4557dbb..cf0c97555c1 100644
--- a/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v70/PopulateLiveMeasuresTest/initial.sql
+++ b/server/sonar-db-migration/src/test/resources/org/sonar/server/platform/db/migration/version/v70/PopulateLiveMeasuresTest/initial.sql
@@ -72,6 +72,8 @@ CREATE TABLE "SNAPSHOTS" (
"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");
@@ -89,7 +91,12 @@ CREATE TABLE "LIVE_MEASURES" (
"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" (
@@ -111,6 +118,4 @@ 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");