/**
* Generate SQL queries to update multiple column types from a table.
*
- * 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.
- *
+ * Note that this operation will not be re-entrant on:
+ * <ul>
+ * <li>Oracle 11G (may raise {@code ORA-01442: column to be modified to NOT NULL is already NOT NULL} or
+ * {@code ORA-01451: column to be modified to NULL cannot be modified to NULL})</li>
+ * </ul>
*/
public class AlterColumnsTypeBuilder {
+ private static final String ALTER_TABLE = "ALTER TABLE ";
+ private static final String ALTER_COLUMN = "ALTER COLUMN ";
+
private final Dialect dialect;
private final String tableName;
private final List<ColumnDef> columnDefs = newArrayList();
}
private List<String> createPostgresQuery() {
- StringBuilder sql = new StringBuilder("ALTER TABLE " + tableName + " ");
- addColumns(sql, "ALTER COLUMN ", "TYPE ", true);
+ StringBuilder sql = new StringBuilder(ALTER_TABLE + tableName + " ");
+ for (Iterator<ColumnDef> columnDefIterator = columnDefs.iterator(); columnDefIterator.hasNext();) {
+ ColumnDef columnDef = columnDefIterator.next();
+ sql.append(ALTER_COLUMN);
+ addColumn(sql, columnDef, "TYPE ", false);
+ sql.append(", ");
+ sql.append(ALTER_COLUMN);
+ sql.append(columnDef.getName());
+ sql.append(' ').append(columnDef.isNullable() ? "DROP" : "SET").append(" NOT NULL");
+ if (columnDefIterator.hasNext()) {
+ sql.append(", ");
+ }
+ }
return Collections.singletonList(sql.toString());
}
private List<String> createMySqlQuery() {
- StringBuilder sql = new StringBuilder("ALTER TABLE " + tableName + " ");
+ StringBuilder sql = new StringBuilder(ALTER_TABLE + tableName + " ");
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, "", "", false);
+ StringBuilder sql = new StringBuilder(ALTER_TABLE + tableName + " ").append("MODIFY (");
+ addColumns(sql, "", "", true);
sql.append(")");
return Collections.singletonList(sql.toString());
}
private List<String> createMsSqlAndH2Queries() {
List<String> sqls = new ArrayList<>();
for (ColumnDef columnDef : columnDefs) {
- StringBuilder defaultQuery = new StringBuilder("ALTER TABLE " + tableName + " ");
- defaultQuery.append("ALTER COLUMN ");
+ StringBuilder defaultQuery = new StringBuilder(ALTER_TABLE + tableName + " ");
+ defaultQuery.append(ALTER_COLUMN);
addColumn(defaultQuery, columnDef, "", true);
sqls.add(defaultQuery.toString());
}
.append(" ")
.append(typePrefix)
.append(columnDef.generateSqlType(dialect));
- if (!columnDef.isNullable() && addNotNullableProperty) {
- sql.append(" NOT NULL");
+ if (addNotNullableProperty) {
+ sql.append(columnDef.isNullable() ? " NULL" : " NOT NULL");
}
}
@Test
public void update_columns_on_h2() {
assertThat(createSampleBuilder(new H2()).build())
- .containsOnly("ALTER TABLE issues ALTER COLUMN value DOUBLE", "ALTER TABLE issues ALTER COLUMN name VARCHAR (10)");
+ .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)", "ALTER TABLE issues ALTER COLUMN name NVARCHAR (10)");
+ .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_postgres() {
assertThat(createSampleBuilder(new PostgreSql()).build())
- .containsOnly("ALTER TABLE issues ALTER COLUMN value TYPE NUMERIC (30,20), ALTER COLUMN name TYPE VARCHAR (10)");
+ .containsOnly("ALTER TABLE issues " +
+ "ALTER COLUMN value TYPE NUMERIC (30,20), ALTER COLUMN value DROP NOT NULL, " +
+ "ALTER COLUMN name TYPE VARCHAR (10), ALTER COLUMN name DROP NOT NULL");
}
@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");
+ .containsOnly("ALTER TABLE issues ALTER COLUMN name TYPE VARCHAR (10), ALTER COLUMN name SET 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)");
+ .containsOnly("ALTER TABLE issues MODIFY COLUMN value DECIMAL (30,20) NULL, MODIFY COLUMN name VARCHAR (10) NULL");
}
@Test
@Test
public void update_columns_on_oracle() {
assertThat(createSampleBuilder(new Oracle()).build())
- .containsOnly("ALTER TABLE issues MODIFY (value NUMERIC (30,20), name VARCHAR (10))");
+ .containsOnly("ALTER TABLE issues MODIFY (value NUMERIC (30,20) NULL, name VARCHAR (10) NULL)");
}
@Test
- public void not_nullable_column_are_ignored_on_oracle() {
+ public void update_not_nullable_column_on_oracle() {
assertThat(createNotNullableBuilder(new Oracle()).build())
- .containsOnly("ALTER TABLE issues MODIFY (name VARCHAR (10))");
+ .containsOnly("ALTER TABLE issues MODIFY (name VARCHAR (10) NOT NULL)");
}
@Test
private AlterColumnsTypeBuilder createNotNullableBuilder(Dialect dialect) {
return new AlterColumnsTypeBuilder(dialect, TABLE_NAME)
.updateColumn(
- newVarcharColumnDefBuilder()
- .setColumnName("name")
- .setLimit(10)
- .setIsNullable(false)
- .build());
+ newVarcharColumnDefBuilder()
+ .setColumnName("name")
+ .setLimit(10)
+ .setIsNullable(false)
+ .build());
}
}