use of liquibase.structure.core.Column in project liquibase by liquibase.
the class MssqlIntegrationTest method dataTypeParamsTest.
@Test
public /**
* When snapshotting an MSSQL database, size information is included for
* XML, SMALLMONEY, HIERARCHYID, DATETIME2, IMAGE, and DATETIMEOFFSET even when the default precisions (if
* applicable at all) are used. Default sizes/precisions should not be transferred into resulting ChangeLogs/
* snapshots.
*
* Reference: https://liquibase.jira.com/browse/CORE-1515
*/
void dataTypeParamsTest() throws Exception {
assumeNotNull(this.getDatabase());
clearDatabase();
Liquibase liquibase = createLiquibase("changelogs/mssql/issues/data.type.params.xml");
liquibase.update((String) null);
DatabaseSnapshot snapshot = SnapshotGeneratorFactory.getInstance().createSnapshot(CatalogAndSchema.DEFAULT, this.getDatabase(), new SnapshotControl(getDatabase()));
for (Table table : snapshot.get(Table.class)) {
if (getDatabase().isLiquibaseObject(table)) {
continue;
}
for (Column column : table.getColumns()) {
String expectedType = column.getName().split("_")[0];
String foundTypeDefinition = DataTypeFactory.getInstance().from(column.getType(), new MSSQLDatabase()).toDatabaseDataType(getDatabase()).toString();
assertFalse("Parameter found in " + table.getName() + "." + column.getName(), foundTypeDefinition.contains("("));
}
}
}
use of liquibase.structure.core.Column in project liquibase by liquibase.
the class MssqlIntegrationTest method defaultValuesTests.
@Test
public void defaultValuesTests() throws Exception {
clearDatabase();
assumeNotNull(this.getDatabase());
Liquibase liquibase = createLiquibase("changelogs/mssql/issues/default.values.xml");
liquibase.update((String) null);
DatabaseSnapshot snapshot = SnapshotGeneratorFactory.getInstance().createSnapshot(CatalogAndSchema.DEFAULT, this.getDatabase(), new SnapshotControl(getDatabase()));
for (Table table : snapshot.get(Table.class)) {
for (Column column : table.getColumns()) {
if (column.getName().toLowerCase().endsWith("_default")) {
Object defaultValue = column.getDefaultValue();
assertNotNull("Null default value for " + table.getName() + "." + column.getName(), defaultValue);
if (column.getName().toLowerCase().contains("date") || column.getName().toLowerCase().contains("time")) {
if (defaultValue instanceof String) {
assertTrue(defaultValue.equals("2017-12-09 23:52:39.1234567 +01:00"));
} else if (defaultValue instanceof DatabaseFunction) {
((DatabaseFunction) defaultValue).getValue().contains("type datetimeoffset");
} else if (defaultValue instanceof Time) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(((Date) defaultValue));
assertEquals(23, calendar.get(Calendar.HOUR_OF_DAY));
assertEquals(52, calendar.get(Calendar.MINUTE));
assertEquals(39, calendar.get(Calendar.SECOND));
} else {
assertTrue("Unexpected default type " + defaultValue.getClass().getName() + " for " + table.getName() + "." + column.getName(), defaultValue instanceof Date);
Calendar calendar = Calendar.getInstance();
calendar.setTime(((Date) defaultValue));
assertEquals(9, calendar.get(Calendar.DAY_OF_MONTH));
assertEquals(11, calendar.get(Calendar.MONTH));
assertEquals(2017, calendar.get(Calendar.YEAR));
}
} else if (column.getName().toLowerCase().contains("char_")) {
assertTrue("Unexpected default type " + defaultValue.getClass().getName() + " for " + table.getName() + "." + column.getName(), defaultValue instanceof String);
} else if (column.getName().toLowerCase().contains("binary_")) {
assertTrue("Unexpected default type " + defaultValue.getClass().getName() + " for " + table.getName() + "." + column.getName(), defaultValue instanceof DatabaseFunction);
} else if (column.getName().toLowerCase().contains("bit_")) {
// todo: test better. Bits are handled odd
} else {
assertTrue("Unexpected default type " + defaultValue.getClass().getName() + " for " + table.getName() + "." + column.getName(), defaultValue instanceof Number);
assertEquals(1, ((Number) defaultValue).intValue());
}
}
}
}
}
use of liquibase.structure.core.Column in project liquibase by liquibase.
the class LoadDataChange method retrieveMissingColumnLoadTypes.
/**
* Iterate through the List of LoadDataColumnConfig and ask the database for any column types that we have
* no data type of.
*
* @param columns a list of LoadDataColumnConfigs to process
*/
@SuppressWarnings("CommentedOutCodeLine")
private void retrieveMissingColumnLoadTypes(List<LoadDataColumnConfig> columns, Database database) throws DatabaseException {
// If no column is missing type information, we are already done.
if (columns.stream().noneMatch(c -> c.getType() == null)) {
return;
}
// Snapshot the database table
CatalogAndSchema catalogAndSchema = new CatalogAndSchema(getCatalogName(), getSchemaName());
catalogAndSchema = catalogAndSchema.standardize(database);
Table targetTable = new Table(catalogAndSchema.getCatalogName(), catalogAndSchema.getSchemaName(), database.correctObjectName(getTableName(), Table.class));
Table snapshotOfTable;
try {
snapshotOfTable = SnapshotGeneratorFactory.getInstance().createSnapshot(targetTable, database, new SnapshotControl(database, Table.class, Column.class));
} catch (InvalidExampleException e) {
throw new DatabaseException(e);
}
if (snapshotOfTable == null) {
LOG.warning(String.format(coreBundle.getString("could.not.snapshot.table.to.get.the.missing.column.type.information"), database.escapeTableName(targetTable.getSchema().getCatalogName(), targetTable.getSchema().getName(), targetTable.getName())));
return;
}
// Save the columns of the database table in a lookup table
Map<String, Column> tableColumns = new HashMap<>();
for (Column c : snapshotOfTable.getColumns()) {
// Normalise the LoadDataColumnConfig column names to the database
tableColumns.put(database.correctObjectName(c.getName(), Column.class), c);
}
/* The above is the JDK7 version of:
snapshotOfTable.getColumns().forEach(c -> tableColumns.put(c.getName(), c));
*/
// Normalise the LoadDataColumnConfig column names to the database
Map<String, LoadDataColumnConfig> columnConfigs = new HashMap<>();
for (LoadDataColumnConfig c : columns) {
columnConfigs.put(database.correctObjectName(c.getName(), Column.class), c);
}
for (Map.Entry<String, LoadDataColumnConfig> entry : columnConfigs.entrySet()) {
if (entry.getValue().getType() != null) {
continue;
}
LoadDataColumnConfig columnConfig = entry.getValue();
Column c = tableColumns.get(entry.getKey());
if (null == c) {
LOG.severe(String.format(coreBundle.getString("unable.to.find.column.in.table"), columnConfig.getName(), snapshotOfTable));
} else {
DataType dataType = c.getType();
if (dataType == null) {
LOG.warning(String.format(coreBundle.getString("unable.to.find.load.data.type"), columnConfig.toString(), snapshotOfTable));
columnConfig.setType(LOAD_DATA_TYPE.STRING);
} else {
LiquibaseDataType liquibaseDataType = DataTypeFactory.getInstance().fromDescription(dataType.toString(), database);
if (liquibaseDataType != null) {
columnConfig.setType(liquibaseDataType.getLoadTypeName());
} else {
LOG.warning(String.format(coreBundle.getString("unable.to.convert.load.data.type"), columnConfig.toString(), snapshotOfTable, dataType));
}
}
}
}
/* The above is the JDK7 version of:
columnConfigs.entrySet().stream()
.filter(entry -> entry.getValue().getType() == null)
.forEach(entry -> {
LoadDataColumnConfig columnConfig = entry.getValue();
DataType dataType = tableColumns.get(entry.getKey()).getType();
if (dataType == null) {
LOG.warning(String.format(coreBundle.getString("unable.to.find.load.data.type"),
columnConfig.toString(), snapshotOfTable.toString() ));
columnConfig.setType(LOAD_DATA_TYPE.STRING.toString());
} else {
LiquibaseDataType liquibaseDataType = DataTypeFactory.getInstance()
.fromDescription(dataType.toString(), database);
if (liquibaseDataType != null) {
columnConfig.setType(liquibaseDataType.getLoadTypeName().toString());
} else {
LOG.warning(String.format(coreBundle.getString("unable.to.convert.load.data.type"),
columnConfig.toString(), snapshotOfTable.toString(), liquibaseDataType.toString()));
}
}
}
);
*/
}
use of liquibase.structure.core.Column in project liquibase by liquibase.
the class MergeColumnChange method generateStatements.
@Override
public SqlStatement[] generateStatements(final Database database) {
List<SqlStatement> statements = new ArrayList<>();
AddColumnChange addNewColumnChange = new AddColumnChange();
addNewColumnChange.setSchemaName(schemaName);
addNewColumnChange.setTableName(getTableName());
final AddColumnConfig columnConfig = new AddColumnConfig();
columnConfig.setName(getFinalColumnName());
columnConfig.setType(getFinalColumnType());
addNewColumnChange.addColumn(columnConfig);
statements.addAll(Arrays.asList(addNewColumnChange.generateStatements(database)));
String updateStatement = "";
if (database instanceof MySQLDatabase || database instanceof MariaDBDatabase) {
updateStatement = "UPDATE " + database.escapeTableName(getCatalogName(), getSchemaName(), getTableName()) + " SET " + database.escapeObjectName(getFinalColumnName(), Column.class) + " = " + database.getConcatSql("'" + getJoinString() + "'", database.escapeObjectName(getColumn1Name(), Column.class), database.escapeObjectName(getColumn2Name(), Column.class));
} else {
updateStatement = "UPDATE " + database.escapeTableName(getCatalogName(), getSchemaName(), getTableName()) + " SET " + database.escapeObjectName(getFinalColumnName(), Column.class) + " = " + database.getConcatSql(database.escapeObjectName(getColumn1Name(), Column.class), "'" + getJoinString() + "'", database.escapeObjectName(getColumn2Name(), Column.class));
}
statements.add(new RawSqlStatement(updateStatement));
if (database instanceof SQLiteDatabase) {
/* nolgpl: implement */
// Since SQLite does not support a Merge column statement,
SQLiteDatabase.AlterTableVisitor alterTableVisitor = new SQLiteDatabase.AlterTableVisitor() {
@Override
public ColumnConfig[] getColumnsToAdd() {
// This gets called after
ColumnConfig[] columnConfigs = new ColumnConfig[1];
ColumnConfig mergedColumn = new ColumnConfig();
mergedColumn.setName(getFinalColumnName());
mergedColumn.setType(getFinalColumnType());
columnConfigs[0] = mergedColumn;
return columnConfigs;
}
@Override
public boolean copyThisColumn(ColumnConfig column) {
// don't create columns that are merged
return !column.getName().equals(getColumn1Name()) && !column.getName().equals(getColumn2Name());
}
@Override
public boolean createThisColumn(ColumnConfig column) {
// don't copy columns that are merged
return !column.getName().equals(getColumn1Name()) && !column.getName().equals(getColumn2Name());
}
@Override
public boolean createThisIndex(Index index) {
// skip the index if it has old columns
for (Column column : index.getColumns()) {
if (column.getName().equals(getColumn1Name()) || column.getName().equals(getColumn2Name())) {
return false;
}
}
return true;
}
};
List<SqlStatement> workAroundStatements = null;
try {
workAroundStatements = SQLiteDatabase.getAlterTableStatements(alterTableVisitor, database, getCatalogName(), getSchemaName(), getTableName());
statements.addAll(workAroundStatements);
} catch (DatabaseException e) {
throw new UnexpectedLiquibaseException(e);
}
} else {
// ...if it is not a SQLite database
DropColumnChange dropColumn1Change = new DropColumnChange();
dropColumn1Change.setSchemaName(schemaName);
dropColumn1Change.setTableName(getTableName());
dropColumn1Change.setColumnName(getColumn1Name());
statements.addAll(Arrays.asList(dropColumn1Change.generateStatements(database)));
DropColumnChange dropColumn2Change = new DropColumnChange();
dropColumn2Change.setSchemaName(schemaName);
dropColumn2Change.setTableName(getTableName());
dropColumn2Change.setColumnName(getColumn2Name());
statements.addAll(Arrays.asList(dropColumn2Change.generateStatements(database)));
}
return statements.toArray(new SqlStatement[statements.size()]);
}
use of liquibase.structure.core.Column in project liquibase by liquibase.
the class MissingColumnChangeGenerator method fixMissing.
@Override
public Change[] fixMissing(DatabaseObject missingObject, DiffOutputControl control, Database referenceDatabase, Database comparisonDatabase, ChangeGeneratorChain chain) {
Column column = (Column) missingObject;
if (column.getRelation() instanceof View) {
return null;
}
if (column.getRelation().getSnapshotId() == null) {
// not an actual table, maybe an alias, maybe in a different schema. Don't fix it.
return null;
}
AddColumnChange change = createAddColumnChange();
change.setTableName(column.getRelation().getName());
if (control.getIncludeCatalog()) {
change.setCatalogName(column.getRelation().getSchema().getCatalogName());
}
if (control.getIncludeSchema()) {
change.setSchemaName(column.getRelation().getSchema().getName());
}
AddColumnConfig columnConfig = createAddColumnConfig();
columnConfig.setName(column.getName());
String dataType = column.getType().toString();
columnConfig.setType(dataType);
MissingTableChangeGenerator.setDefaultValue(columnConfig, column, comparisonDatabase);
Column.AutoIncrementInformation autoIncrementInfo = column.getAutoIncrementInformation();
if (autoIncrementInfo != null) {
columnConfig.setAutoIncrement(true);
columnConfig.setGenerationType(autoIncrementInfo.getGenerationType());
columnConfig.setDefaultOnNull(autoIncrementInfo.getDefaultOnNull());
}
if (column.getRemarks() != null) {
columnConfig.setRemarks(column.getRemarks());
}
ConstraintsConfig constraintsConfig = columnConfig.getConstraints();
if ((column.isNullable() != null) && !column.isNullable()) {
if (constraintsConfig == null) {
constraintsConfig = new ConstraintsConfig();
}
constraintsConfig.setNullable(false);
constraintsConfig.setNotNullConstraintName(column.getAttribute("notNullConstraintName", String.class));
if (!column.getValidateNullable()) {
constraintsConfig.setValidateNullable(false);
}
}
if (constraintsConfig != null) {
columnConfig.setConstraints(constraintsConfig);
}
change.addColumn(columnConfig);
return new Change[] { change };
}
Aggregations