Search in sources :

Example 31 with Column

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("("));
        }
    }
}
Also used : Liquibase(liquibase.Liquibase) Table(liquibase.structure.core.Table) Column(liquibase.structure.core.Column) MSSQLDatabase(liquibase.database.core.MSSQLDatabase) DatabaseSnapshot(liquibase.snapshot.DatabaseSnapshot) SnapshotControl(liquibase.snapshot.SnapshotControl) Test(org.junit.Test)

Example 32 with Column

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());
                }
            }
        }
    }
}
Also used : Liquibase(liquibase.Liquibase) Table(liquibase.structure.core.Table) DatabaseFunction(liquibase.statement.DatabaseFunction) Column(liquibase.structure.core.Column) Calendar(java.util.Calendar) Time(java.sql.Time) DatabaseSnapshot(liquibase.snapshot.DatabaseSnapshot) SnapshotControl(liquibase.snapshot.SnapshotControl) Date(java.util.Date) Test(org.junit.Test)

Example 33 with Column

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()));
                        }
                    }
                }
        );
        */
}
Also used : Table(liquibase.structure.core.Table) LiquibaseDataType(liquibase.datatype.LiquibaseDataType) CatalogAndSchema(liquibase.CatalogAndSchema) InvalidExampleException(liquibase.snapshot.InvalidExampleException) Column(liquibase.structure.core.Column) DataType(liquibase.structure.core.DataType) LiquibaseDataType(liquibase.datatype.LiquibaseDataType) SnapshotControl(liquibase.snapshot.SnapshotControl)

Example 34 with Column

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()]);
}
Also used : RawSqlStatement(liquibase.statement.core.RawSqlStatement) ArrayList(java.util.ArrayList) Index(liquibase.structure.core.Index) RawSqlStatement(liquibase.statement.core.RawSqlStatement) SqlStatement(liquibase.statement.SqlStatement) Column(liquibase.structure.core.Column) AlterTableVisitor(liquibase.database.core.SQLiteDatabase.AlterTableVisitor) AlterTableVisitor(liquibase.database.core.SQLiteDatabase.AlterTableVisitor) DatabaseException(liquibase.exception.DatabaseException) UnexpectedLiquibaseException(liquibase.exception.UnexpectedLiquibaseException)

Example 35 with Column

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 };
}
Also used : Column(liquibase.structure.core.Column) ConstraintsConfig(liquibase.change.ConstraintsConfig) AddColumnConfig(liquibase.change.AddColumnConfig) Change(liquibase.change.Change) AddColumnChange(liquibase.change.core.AddColumnChange) AddColumnChange(liquibase.change.core.AddColumnChange) View(liquibase.structure.core.View)

Aggregations

Column (liquibase.structure.core.Column)43 Table (liquibase.structure.core.Table)22 Change (liquibase.change.Change)8 SnapshotControl (liquibase.snapshot.SnapshotControl)8 Index (liquibase.structure.core.Index)8 DatabaseSnapshot (liquibase.snapshot.DatabaseSnapshot)7 DatabaseObject (liquibase.structure.DatabaseObject)6 Test (org.junit.Test)6 DatabaseException (liquibase.exception.DatabaseException)5 SqlStatement (liquibase.statement.SqlStatement)5 Schema (liquibase.structure.core.Schema)5 UniqueConstraint (liquibase.structure.core.UniqueConstraint)5 ArrayList (java.util.ArrayList)4 MSSQLDatabase (liquibase.database.core.MSSQLDatabase)4 UnexpectedLiquibaseException (liquibase.exception.UnexpectedLiquibaseException)4 CatalogAndSchema (liquibase.CatalogAndSchema)3 Liquibase (liquibase.Liquibase)3 AbstractIntegrationTest (liquibase.dbtest.AbstractIntegrationTest)3 RawSqlStatement (liquibase.statement.core.RawSqlStatement)3 PrimaryKey (liquibase.structure.core.PrimaryKey)3