}
private List<String> createOracleQuery() {
- StringBuilder sql = new StringBuilder(ALTER_TABLE + tableName + " ").append("MODIFY (");
- addColumns(sql, "", "", true);
- sql.append(")");
- return Collections.singletonList(sql.toString());
+ List<String> sqls = new ArrayList<>();
+ for (ColumnDef columnDef : columnDefs) {
+ StringBuilder sql = new StringBuilder(ALTER_TABLE + tableName + " ").append("MODIFY (");
+ addColumn(sql, columnDef, "", true);
+ sql.append(")");
+ sqls.add(sql.toString());
+ }
+ return sqls;
}
private List<String> createMsSqlAndH2Queries() {
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
+import java.util.regex.Pattern;
import org.apache.commons.dbutils.DbUtils;
import org.sonar.db.Database;
import org.sonar.db.dialect.Dialect;
-import static java.lang.String.*;
+import static java.lang.String.format;
import static java.util.Arrays.asList;
public abstract class DdlChange implements MigrationStep {
}
public static class Context {
+ private static final int ERROR_HANDLING_THRESHOLD = 10;
+ // the tricky regexp is required to match "NULL" but not "NOT NULL"
+ private final Pattern nullPattern = Pattern.compile("\\h?(?<!NOT )NULL");
+ private final Pattern notNullPattern = Pattern.compile("\\h?NOT NULL");
private final Connection writeConnection;
public Context(Connection writeConnection) {
}
public void execute(String sql) throws SQLException {
+ execute(sql, sql, 0);
+ }
+
+ public void execute(String original, String sql, int errorCount) throws SQLException {
try {
UpsertImpl.create(writeConnection, sql).execute().commit();
+ } catch (SQLException e) {
+ if (errorCount < ERROR_HANDLING_THRESHOLD) {
+ String message = e.getMessage();
+ if (message.contains("ORA-01451")) {
+ String newSql = nullPattern.matcher(sql).replaceFirst("");
+ execute(original, newSql, errorCount + 1);
+ return;
+ } else if (message.contains("ORA-01442")) {
+ String newSql = notNullPattern.matcher(sql).replaceFirst("");
+ execute(original, newSql, errorCount + 1);
+ return;
+ }
+ }
+ throw new IllegalStateException(messageForIseOf(original, sql, errorCount), e);
} catch (Exception e) {
- throw new IllegalStateException(format("Fail to execute %s", sql), e);
+ throw new IllegalStateException(messageForIseOf(original, sql, errorCount), e);
+ }
+ }
+
+ private static String messageForIseOf(String original, String sql, int errorCount) {
+ if (!original.equals(sql) || errorCount > 0) {
+ return format("Fail to execute %s %n (caught %s error, original was %s)", sql, errorCount, original);
+ } else {
+ return format("Fail to execute %s", sql);
}
}
@Test
public void update_columns_on_h2() {
assertThat(createSampleBuilder(new H2()).build())
- .containsOnly("ALTER TABLE issues ALTER COLUMN value DOUBLE NULL", "ALTER TABLE issues ALTER COLUMN name VARCHAR (10) NULL");
+ .containsOnly(
+ "ALTER TABLE issues ALTER COLUMN value DOUBLE NULL",
+ "ALTER TABLE issues ALTER COLUMN name VARCHAR (10) NULL");
}
@Test
@Test
public void update_columns_on_mssql() {
assertThat(createSampleBuilder(new MsSql()).build())
- .containsOnly("ALTER TABLE issues ALTER COLUMN value DECIMAL (30,20) NULL", "ALTER TABLE issues ALTER COLUMN name NVARCHAR (10) NULL");
+ .containsOnly(
+ "ALTER TABLE issues ALTER COLUMN value DECIMAL (30,20) NULL",
+ "ALTER TABLE issues ALTER COLUMN name NVARCHAR (10) NULL");
}
@Test
@Test
public void update_columns_on_oracle() {
assertThat(createSampleBuilder(new Oracle()).build())
- .containsOnly("ALTER TABLE issues MODIFY (value NUMERIC (30,20) NULL, name VARCHAR (10) NULL)");
+ .containsOnly(
+ "ALTER TABLE issues MODIFY (value NUMERIC (30,20) NULL)",
+ "ALTER TABLE issues MODIFY (name VARCHAR (10) NULL)");
}
@Test