diff options
11 files changed, 103 insertions, 22 deletions
diff --git a/sonar-db/src/main/java/org/sonar/db/version/AlterColumnsBuilder.java b/sonar-db/src/main/java/org/sonar/db/version/AlterColumnsTypeBuilder.java index e162d2a522f..a402b3c4444 100644 --- a/sonar-db/src/main/java/org/sonar/db/version/AlterColumnsBuilder.java +++ b/sonar-db/src/main/java/org/sonar/db/version/AlterColumnsTypeBuilder.java @@ -34,20 +34,24 @@ import static com.google.common.collect.Lists.newArrayList; /** * Generate SQL queries to update multiple column types from a table. * - * Note that it's not possible to change the nullable state of a column (Because on Oracle, sending a query to set a column to be nullable when it's already nullable will fail). + * This class should only be used to change the type of a column, as the nullable state is only used to not loose the nullable information. + * Indeed, on MsSQL, not setting the nullable state will set the column to NULL, but on Oracle setting a column NOT NULL when it's already NOT NULL will fail). + * + * The nullable information will then be ignored on Oracle. + * */ -public class AlterColumnsBuilder { +public class AlterColumnsTypeBuilder { private final Dialect dialect; private final String tableName; private final List<ColumnDef> columnDefs = newArrayList(); - public AlterColumnsBuilder(Dialect dialect, String tableName) { + public AlterColumnsTypeBuilder(Dialect dialect, String tableName) { this.dialect = dialect; this.tableName = tableName; } - public AlterColumnsBuilder updateColumn(ColumnDef columnDef) { + public AlterColumnsTypeBuilder updateColumn(ColumnDef columnDef) { columnDefs.add(columnDef); return this; } @@ -70,19 +74,19 @@ public class AlterColumnsBuilder { private List<String> createPostgresQuery() { StringBuilder sql = new StringBuilder("ALTER TABLE " + tableName + " "); - addColumns(sql, "ALTER COLUMN ", "TYPE "); + addColumns(sql, "ALTER COLUMN ", "TYPE ", true); return Collections.singletonList(sql.toString()); } private List<String> createMySqlQuery() { StringBuilder sql = new StringBuilder("ALTER TABLE " + tableName + " "); - addColumns(sql, "MODIFY COLUMN ", ""); + addColumns(sql, "MODIFY COLUMN ", "", true); return Collections.singletonList(sql.toString()); } private List<String> createOracleQuery() { StringBuilder sql = new StringBuilder("ALTER TABLE " + tableName + " ").append("MODIFY ("); - addColumns(sql, "", ""); + addColumns(sql, "", "", false); sql.append(")"); return Collections.singletonList(sql.toString()); } @@ -92,27 +96,30 @@ public class AlterColumnsBuilder { for (ColumnDef columnDef : columnDefs) { StringBuilder defaultQuery = new StringBuilder("ALTER TABLE " + tableName + " "); defaultQuery.append("ALTER COLUMN "); - addColumn(defaultQuery, columnDef, ""); + addColumn(defaultQuery, columnDef, "", true); sqls.add(defaultQuery.toString()); } return sqls; } - private void addColumns(StringBuilder sql, String updateKeyword, String typePrefix) { + private void addColumns(StringBuilder sql, String updateKeyword, String typePrefix, boolean addNotNullableProperty) { for (Iterator<ColumnDef> columnDefIterator = columnDefs.iterator(); columnDefIterator.hasNext();) { sql.append(updateKeyword); - addColumn(sql, columnDefIterator.next(), typePrefix); + addColumn(sql, columnDefIterator.next(), typePrefix, addNotNullableProperty); if (columnDefIterator.hasNext()) { sql.append(", "); } } } - private void addColumn(StringBuilder sql, ColumnDef columnDef, String typePrefix) { + private void addColumn(StringBuilder sql, ColumnDef columnDef, String typePrefix, boolean addNotNullableProperty) { sql.append(columnDef.getName()) .append(" ") .append(typePrefix) .append(columnDef.generateSqlType(dialect)); + if (!columnDef.isNullable() && addNotNullableProperty) { + sql.append(" NOT NULL"); + } } } diff --git a/sonar-db/src/main/java/org/sonar/db/version/BigDecimalColumnDef.java b/sonar-db/src/main/java/org/sonar/db/version/BigDecimalColumnDef.java index 773913f6588..15e7b0fda66 100644 --- a/sonar-db/src/main/java/org/sonar/db/version/BigDecimalColumnDef.java +++ b/sonar-db/src/main/java/org/sonar/db/version/BigDecimalColumnDef.java @@ -45,7 +45,7 @@ public class BigDecimalColumnDef extends AbstractColumnDef { @CheckForNull private String columnName; - private boolean isNullable; + private boolean isNullable = true; public Builder setColumnName(String columnName) { this.columnName = validateColumnName(columnName); diff --git a/sonar-db/src/main/java/org/sonar/db/version/ClobColumnDef.java b/sonar-db/src/main/java/org/sonar/db/version/ClobColumnDef.java index f96a9886c82..c7a3665c4f4 100644 --- a/sonar-db/src/main/java/org/sonar/db/version/ClobColumnDef.java +++ b/sonar-db/src/main/java/org/sonar/db/version/ClobColumnDef.java @@ -53,7 +53,7 @@ public class ClobColumnDef extends AbstractColumnDef { @CheckForNull private String columnName; - private boolean isNullable; + private boolean isNullable = true; public Builder setColumnName(String columnName) { this.columnName = validateColumnName(columnName); diff --git a/sonar-db/src/main/java/org/sonar/db/version/DecimalColumnDef.java b/sonar-db/src/main/java/org/sonar/db/version/DecimalColumnDef.java index b2a0c6cb0eb..276a7c40c74 100644 --- a/sonar-db/src/main/java/org/sonar/db/version/DecimalColumnDef.java +++ b/sonar-db/src/main/java/org/sonar/db/version/DecimalColumnDef.java @@ -77,7 +77,7 @@ public class DecimalColumnDef extends AbstractColumnDef { private String columnName; private int precision = DEFAULT_PRECISION; private int scale = DEFAULT_SCALE; - private boolean isNullable = false; + private boolean isNullable = true; public Builder setColumnName(String columnName) { this.columnName = validateColumnName(columnName); diff --git a/sonar-db/src/main/java/org/sonar/db/version/VarcharColumnDef.java b/sonar-db/src/main/java/org/sonar/db/version/VarcharColumnDef.java index c093b4b6a8b..400283c128b 100644 --- a/sonar-db/src/main/java/org/sonar/db/version/VarcharColumnDef.java +++ b/sonar-db/src/main/java/org/sonar/db/version/VarcharColumnDef.java @@ -62,7 +62,7 @@ public class VarcharColumnDef extends AbstractColumnDef { @CheckForNull private String columnName; - private boolean isNullable; + private boolean isNullable = true; public Builder setColumnName(String columnName) { this.columnName = validateColumnName(columnName); diff --git a/sonar-db/src/main/java/org/sonar/db/version/v52/IncreasePrecisionOfNumerics.java b/sonar-db/src/main/java/org/sonar/db/version/v52/IncreasePrecisionOfNumerics.java index 9c4ad3ee737..317fa037294 100644 --- a/sonar-db/src/main/java/org/sonar/db/version/v52/IncreasePrecisionOfNumerics.java +++ b/sonar-db/src/main/java/org/sonar/db/version/v52/IncreasePrecisionOfNumerics.java @@ -23,7 +23,7 @@ package org.sonar.db.version.v52; import java.sql.SQLException; import java.util.List; import org.sonar.db.Database; -import org.sonar.db.version.AlterColumnsBuilder; +import org.sonar.db.version.AlterColumnsTypeBuilder; import org.sonar.db.version.DdlChange; import static org.sonar.db.version.DecimalColumnDef.newDecimalColumnDefBuilder; @@ -64,7 +64,7 @@ public class IncreasePrecisionOfNumerics extends DdlChange { } private List<String> generateSql(String table, String... columns) { - AlterColumnsBuilder columnsBuilder = new AlterColumnsBuilder(getDatabase().getDialect(), table); + AlterColumnsTypeBuilder columnsBuilder = new AlterColumnsTypeBuilder(getDatabase().getDialect(), table); for (String column : columns) { columnsBuilder.updateColumn(newDecimalColumnDefBuilder().setColumnName(column).build()); } diff --git a/sonar-db/src/test/java/org/sonar/db/version/AlterColumnsBuilderTest.java b/sonar-db/src/test/java/org/sonar/db/version/AlterColumnsTypeBuilderTest.java index f0c58e66c74..93128e8ec1c 100644 --- a/sonar-db/src/test/java/org/sonar/db/version/AlterColumnsBuilderTest.java +++ b/sonar-db/src/test/java/org/sonar/db/version/AlterColumnsTypeBuilderTest.java @@ -34,7 +34,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.sonar.db.version.DecimalColumnDef.newDecimalColumnDefBuilder; import static org.sonar.db.version.VarcharColumnDef.newVarcharColumnDefBuilder; -public class AlterColumnsBuilderTest { +public class AlterColumnsTypeBuilderTest { static final String TABLE_NAME = "issues"; @Rule @@ -47,50 +47,92 @@ public class AlterColumnsBuilderTest { } @Test + public void update_not_nullable_column_on_h2() { + assertThat(createNotNullableBuilder(new H2()).build()) + .containsOnly("ALTER TABLE issues ALTER COLUMN name VARCHAR (10) NOT NULL"); + } + + @Test public void update_columns_on_mssql() { assertThat(createSampleBuilder(new MsSql()).build()) .containsOnly("ALTER TABLE issues ALTER COLUMN value DECIMAL (30,20)", "ALTER TABLE issues ALTER COLUMN name NVARCHAR (10)"); } @Test + public void update_not_nullable_column_on_mssql() { + assertThat(createNotNullableBuilder(new MsSql()).build()) + .containsOnly("ALTER TABLE issues ALTER COLUMN name NVARCHAR (10) NOT NULL"); + } + + @Test public void update_columns_on_postgres() { assertThat(createSampleBuilder(new PostgreSql()).build()) .containsOnly("ALTER TABLE issues ALTER COLUMN value TYPE NUMERIC (30,20), ALTER COLUMN name TYPE VARCHAR (10)"); } @Test + public void update_not_nullable_column_on_postgres() { + assertThat(createNotNullableBuilder(new PostgreSql()).build()) + .containsOnly("ALTER TABLE issues ALTER COLUMN name TYPE VARCHAR (10) NOT NULL"); + } + + @Test public void update_columns_on_mysql() { assertThat(createSampleBuilder(new MySql()).build()) .containsOnly("ALTER TABLE issues MODIFY COLUMN value DECIMAL (30,20), MODIFY COLUMN name VARCHAR (10)"); } @Test + public void update_not_nullable_column_on_mysql() { + assertThat(createNotNullableBuilder(new MySql()).build()) + .containsOnly("ALTER TABLE issues MODIFY COLUMN name VARCHAR (10) NOT NULL"); + } + + @Test public void update_columns_on_oracle() { assertThat(createSampleBuilder(new Oracle()).build()) .containsOnly("ALTER TABLE issues MODIFY (value NUMERIC (30,20), name VARCHAR (10))"); } @Test + public void not_nullable_column_are_ignored_on_oracle() { + assertThat(createNotNullableBuilder(new Oracle()).build()) + .containsOnly("ALTER TABLE issues MODIFY (name VARCHAR (10))"); + } + + @Test public void fail_with_ISE_if_no_column() { thrown.expect(IllegalStateException.class); thrown.expectMessage("No column has been defined"); - new AlterColumnsBuilder(new H2(), TABLE_NAME).build(); + new AlterColumnsTypeBuilder(new H2(), TABLE_NAME).build(); } - private AlterColumnsBuilder createSampleBuilder(Dialect dialect) { - return new AlterColumnsBuilder(dialect, TABLE_NAME) + private AlterColumnsTypeBuilder createSampleBuilder(Dialect dialect) { + return new AlterColumnsTypeBuilder(dialect, TABLE_NAME) .updateColumn( newDecimalColumnDefBuilder() .setColumnName("value") .setPrecision(30) .setScale(20) + .setIsNullable(true) .build()) .updateColumn( newVarcharColumnDefBuilder() .setColumnName("name") .setLimit(10) + .setIsNullable(true) .build()); } + private AlterColumnsTypeBuilder createNotNullableBuilder(Dialect dialect) { + return new AlterColumnsTypeBuilder(dialect, TABLE_NAME) + .updateColumn( + newVarcharColumnDefBuilder() + .setColumnName("name") + .setLimit(10) + .setIsNullable(false) + .build()); + } + } diff --git a/sonar-db/src/test/java/org/sonar/db/version/BigDecimalColumnDefTest.java b/sonar-db/src/test/java/org/sonar/db/version/BigDecimalColumnDefTest.java index 286df3841d8..96301f4084f 100644 --- a/sonar-db/src/test/java/org/sonar/db/version/BigDecimalColumnDefTest.java +++ b/sonar-db/src/test/java/org/sonar/db/version/BigDecimalColumnDefTest.java @@ -48,6 +48,16 @@ public class BigDecimalColumnDefTest { } @Test + public void build_string_column_def_with_default_values() throws Exception { + BigDecimalColumnDef def = new BigDecimalColumnDef.Builder() + .setColumnName("issues") + .build(); + + assertThat(def.getName()).isEqualTo("issues"); + assertThat(def.isNullable()).isTrue(); + } + + @Test public void generate_sql_type() throws Exception { BigDecimalColumnDef def = new BigDecimalColumnDef.Builder() .setColumnName("issues") diff --git a/sonar-db/src/test/java/org/sonar/db/version/ClobColumnDefTest.java b/sonar-db/src/test/java/org/sonar/db/version/ClobColumnDefTest.java index 30912f9c9ec..225f85cbb96 100644 --- a/sonar-db/src/test/java/org/sonar/db/version/ClobColumnDefTest.java +++ b/sonar-db/src/test/java/org/sonar/db/version/ClobColumnDefTest.java @@ -47,6 +47,16 @@ public class ClobColumnDefTest { } @Test + public void build_string_column_def_with_default_values() throws Exception { + ClobColumnDef def = new ClobColumnDef.Builder() + .setColumnName("issues") + .build(); + + assertThat(def.getName()).isEqualTo("issues"); + assertThat(def.isNullable()).isTrue(); + } + + @Test public void generate_sql_type() throws Exception { ClobColumnDef def = new ClobColumnDef.Builder() .setColumnName("issues") diff --git a/sonar-db/src/test/java/org/sonar/db/version/DecimalColumnDefTest.java b/sonar-db/src/test/java/org/sonar/db/version/DecimalColumnDefTest.java index f54250ebe07..143b06c44d1 100644 --- a/sonar-db/src/test/java/org/sonar/db/version/DecimalColumnDefTest.java +++ b/sonar-db/src/test/java/org/sonar/db/version/DecimalColumnDefTest.java @@ -102,7 +102,7 @@ public class DecimalColumnDefTest { assertThat(def.getPrecision()).isEqualTo(38); assertThat(def.getScale()).isEqualTo(20); - assertThat(def.isNullable()).isFalse(); + assertThat(def.isNullable()).isTrue(); } @Test diff --git a/sonar-db/src/test/java/org/sonar/db/version/VarcharColumnDefTest.java b/sonar-db/src/test/java/org/sonar/db/version/VarcharColumnDefTest.java index e3810d4a2f4..8464cedd042 100644 --- a/sonar-db/src/test/java/org/sonar/db/version/VarcharColumnDefTest.java +++ b/sonar-db/src/test/java/org/sonar/db/version/VarcharColumnDefTest.java @@ -49,6 +49,18 @@ public class VarcharColumnDefTest { } @Test + public void build_string_column_def_with_default_values() throws Exception { + VarcharColumnDef def = new VarcharColumnDef.Builder() + .setColumnName("issues") + .setLimit(10) + .build(); + + assertThat(def.getName()).isEqualTo("issues"); + assertThat(def.getColumnSize()).isEqualTo(10); + assertThat(def.isNullable()).isTrue(); + } + + @Test public void generate_sql_type() throws Exception { VarcharColumnDef def = new VarcharColumnDef.Builder() .setColumnName("issues") |