Browse Source

SONAR-13948 fix migrations to drop default constraints when dropping column for mssql

tags/8.6.0.39681
Jacek 3 years ago
parent
commit
443044aa50

+ 11
- 2
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v85/DropUnusedPeriodsInSnapshots.java View File

@@ -21,19 +21,28 @@ package org.sonar.server.platform.db.migration.version.v85;

import java.sql.SQLException;
import org.sonar.db.Database;
import org.sonar.db.dialect.MsSql;
import org.sonar.server.platform.db.migration.sql.DropColumnsBuilder;
import org.sonar.server.platform.db.migration.step.DdlChange;
import org.sonar.server.platform.db.migration.version.v85.util.DropMsSQLDefaultConstraintsBuilder;

public class DropUnusedPeriodsInSnapshots extends DdlChange {
private static final String TABLE_NAME = "snapshots";
private static final String[] COLUMNS = {"period2_mode", "period2_param", "period2_date",
"period3_mode", "period3_param", "period3_date", "period4_mode", "period4_param", "period4_date", "period5_mode",
"period5_param", "period5_date"};
private final Database db;

public DropUnusedPeriodsInSnapshots(Database db) {
super(db);
this.db = db;
}

@Override
public void execute(Context context) throws SQLException {
context.execute(new DropColumnsBuilder(getDialect(), TABLE_NAME, "period2_mode", "period2_param", "period2_date",
"period3_mode", "period3_param", "period3_date", "period4_mode", "period4_param", "period4_date", "period5_mode", "period5_param", "period5_date").build());
if (MsSql.ID.equals(db.getDialect().getId())) {
context.execute(new DropMsSQLDefaultConstraintsBuilder(db).setTable(TABLE_NAME).setColumns(COLUMNS).build());
}
context.execute(new DropColumnsBuilder(getDialect(), TABLE_NAME, COLUMNS).build());
}
}

+ 9
- 1
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v85/DropUnusedVariationsInProjectMeasures.java View File

@@ -21,18 +21,26 @@ package org.sonar.server.platform.db.migration.version.v85;

import java.sql.SQLException;
import org.sonar.db.Database;
import org.sonar.db.dialect.MsSql;
import org.sonar.server.platform.db.migration.sql.DropColumnsBuilder;
import org.sonar.server.platform.db.migration.step.DdlChange;
import org.sonar.server.platform.db.migration.version.v85.util.DropMsSQLDefaultConstraintsBuilder;

public class DropUnusedVariationsInProjectMeasures extends DdlChange {
private static final String TABLE_NAME = "project_measures";
private static final String[] COLUMNS = {"variation_value_2", "variation_value_3", "variation_value_4", "variation_value_5"};
private final Database db;

public DropUnusedVariationsInProjectMeasures(Database db) {
super(db);
this.db = db;
}

@Override
public void execute(Context context) throws SQLException {
context.execute(new DropColumnsBuilder(getDialect(), TABLE_NAME, "variation_value_2", "variation_value_3", "variation_value_4", "variation_value_5").build());
if (MsSql.ID.equals(db.getDialect().getId())) {
context.execute(new DropMsSQLDefaultConstraintsBuilder(db).setTable(TABLE_NAME).setColumns(COLUMNS).build());
}
context.execute(new DropColumnsBuilder(getDialect(), TABLE_NAME, COLUMNS).build());
}
}

+ 90
- 0
server/sonar-db-migration/src/main/java/org/sonar/server/platform/db/migration/version/v85/util/DropMsSQLDefaultConstraintsBuilder.java View File

@@ -0,0 +1,90 @@
/*
* SonarQube
* Copyright (C) 2009-2020 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.v85.util;

import com.google.common.base.Preconditions;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.stream.Collectors;
import org.sonar.db.Database;
import org.sonar.db.dialect.MsSql;

import static java.lang.String.format;

public class DropMsSQLDefaultConstraintsBuilder {
private final Database db;
private String tableName;
private String[] columns;

public DropMsSQLDefaultConstraintsBuilder(Database db) {
this.db = db;
}

public DropMsSQLDefaultConstraintsBuilder setTable(String s) {
this.tableName = s;
return this;
}

public DropMsSQLDefaultConstraintsBuilder setColumns(String... columns) {
this.columns = columns;
return this;
}

public List<String> build() throws SQLException {
Preconditions.checkArgument(columns.length > 0, "At least one column expected.");
Preconditions.checkArgument(MsSql.ID.equals(db.getDialect().getId()), "Expected MsSql dialect was: " + db.getDialect().getId());
return getMsSqlDropDefaultConstraintQueries();
}

private List<String> getMsSqlDropDefaultConstraintQueries() throws SQLException {
List<String> dropQueries = new LinkedList<>();
if (MsSql.ID.equals(db.getDialect().getId())) {
List<String> defaultConstraints = getMssqlDefaultConstraints();
for (String defaultConstraintName : defaultConstraints) {
dropQueries.add("ALTER TABLE " + tableName + " DROP CONSTRAINT " + defaultConstraintName);
}
}
return dropQueries;
}

private List<String> getMssqlDefaultConstraints() throws SQLException {
List<String> defaultConstrainNames = new LinkedList<>();
String commaSeparatedListOfColumns = Arrays.stream(columns).map(s -> "'" + s + "'")
.collect(Collectors.joining(","));
try (Connection connection = db.getDataSource().getConnection();
PreparedStatement pstmt = connection
.prepareStatement(format("SELECT d.name FROM sys.tables t "
+ "JOIN sys.default_constraints d ON d.parent_object_id = t.object_id "
+ "JOIN sys.columns c ON c.object_id = t.object_id AND c.column_id = d.parent_column_id "
+ "WHERE t.name = '%s' AND c.name in (%s)", tableName, commaSeparatedListOfColumns));
ResultSet rs = pstmt.executeQuery()) {
while (rs.next()) {
defaultConstrainNames.add(rs.getString(1));
}
}
return defaultConstrainNames;
}

}

+ 77
- 0
server/sonar-db-migration/src/test/java/org/sonar/server/platform/db/migration/version/v85/util/DropMsSQLDefaultConstraintsBuilderTest.java View File

@@ -0,0 +1,77 @@
/*
* SonarQube
* Copyright (C) 2009-2020 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.v85.util;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import javax.sql.DataSource;
import org.junit.Test;
import org.sonar.db.Database;
import org.sonar.db.dialect.H2;
import org.sonar.db.dialect.MsSql;
import org.sonar.db.dialect.Oracle;
import org.sonar.db.dialect.PostgreSql;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class DropMsSQLDefaultConstraintsBuilderTest {

private final Database db = mock(Database.class);

@Test(expected = IllegalArgumentException.class)
public void fail_if_oracle() throws Exception {
when(db.getDialect()).thenReturn(new Oracle());
new DropMsSQLDefaultConstraintsBuilder(db).setTable("snapshots").setColumns("variation_value_2", "variation_value_3").build();
}

@Test(expected = IllegalArgumentException.class)
public void fail_if_h2() throws Exception {
when(db.getDialect()).thenReturn(new H2());
new DropMsSQLDefaultConstraintsBuilder(db).setTable("snapshots").setColumns("variation_value_2", "variation_value_3").build();
}

@Test(expected = IllegalArgumentException.class)
public void fail_if_postgres() throws Exception {
when(db.getDialect()).thenReturn(new PostgreSql());
new DropMsSQLDefaultConstraintsBuilder(db).setTable("snapshots").setColumns("variation_value_2", "variation_value_3").build();
}

@Test
public void generate_queries_for_mssql() throws Exception {
when(db.getDialect()).thenReturn(new MsSql());
DataSource dataSource = mock(DataSource.class);
when(db.getDataSource()).thenReturn(dataSource);
Connection connection = mock(Connection.class);
when(dataSource.getConnection()).thenReturn(connection);
PreparedStatement statement = mock(PreparedStatement.class);
when(connection.prepareStatement(anyString())).thenReturn(statement);
ResultSet rsMock = mock(ResultSet.class);
when(statement.executeQuery()).thenReturn(rsMock);
when(rsMock.next()).thenReturn(true, true, false);
when(rsMock.getString(1)).thenReturn("DF__A1", "DF__A2");

assertThat(new DropMsSQLDefaultConstraintsBuilder(db).setTable("snapshots").setColumns("variation_value_2", "variation_value_3").build())
.containsExactly("ALTER TABLE snapshots DROP CONSTRAINT DF__A1", "ALTER TABLE snapshots DROP CONSTRAINT DF__A2");
}
}

Loading…
Cancel
Save