Search in sources :

Example 6 with LiquibaseDataType

use of liquibase.datatype.LiquibaseDataType in project liquibase by liquibase.

the class CreateTableChange method generateStatements.

@Override
public SqlStatement[] generateStatements(Database database) {
    CreateTableStatement statement = generateCreateTableStatement();
    for (ColumnConfig column : getColumns()) {
        ConstraintsConfig constraints = column.getConstraints();
        boolean isAutoIncrement = (column.isAutoIncrement() != null) && column.isAutoIncrement();
        Object defaultValue = column.getDefaultValueObject();
        LiquibaseDataType columnType = null;
        if (column.getType() != null) {
            columnType = DataTypeFactory.getInstance().fromDescription(column.getType() + (isAutoIncrement ? "{autoIncrement:true}" : ""), database);
            isAutoIncrement |= columnType.isAutoIncrement();
        }
        if ((constraints != null) && (constraints.isPrimaryKey() != null) && constraints.isPrimaryKey()) {
            statement.addPrimaryKeyColumn(column.getName(), columnType, defaultValue, constraints.getValidatePrimaryKey(), constraints.isDeferrable() != null && constraints.isDeferrable(), constraints.isInitiallyDeferred() != null && constraints.isInitiallyDeferred(), constraints.getPrimaryKeyName(), constraints.getPrimaryKeyTablespace());
        } else {
            statement.addColumn(column.getName(), columnType, column.getDefaultValueConstraintName(), defaultValue, column.getRemarks());
        }
        if (constraints != null) {
            if (constraints.isNullable() != null && !constraints.isNullable()) {
                NotNullConstraint notNullConstraint = new NotNullConstraint(column.getName()).setConstraintName(constraints.getNotNullConstraintName()).setValidateNullable(constraints.getValidateNullable() == null ? true : constraints.getValidateNullable());
                statement.addColumnConstraint(notNullConstraint);
            }
            if ((constraints.getReferences() != null) || ((constraints.getReferencedTableName() != null) && (constraints.getReferencedColumnNames() != null))) {
                if (StringUtil.trimToNull(constraints.getForeignKeyName()) == null) {
                    throw new UnexpectedLiquibaseException("createTable with references requires foreignKeyName");
                }
                ForeignKeyConstraint fkConstraint = new ForeignKeyConstraint(constraints.getForeignKeyName(), constraints.getReferences(), constraints.getReferencedTableName(), constraints.getReferencedColumnNames());
                fkConstraint.setReferencedTableCatalogName(constraints.getReferencedTableCatalogName());
                fkConstraint.setReferencedTableSchemaName(constraints.getReferencedTableSchemaName());
                fkConstraint.setColumn(column.getName());
                fkConstraint.setDeleteCascade((constraints.isDeleteCascade() != null) && constraints.isDeleteCascade());
                fkConstraint.setInitiallyDeferred((constraints.isInitiallyDeferred() != null) && constraints.isInitiallyDeferred());
                fkConstraint.setDeferrable((constraints.isDeferrable() != null) && constraints.isDeferrable());
                Boolean validate = constraints.getValidateForeignKey();
                if (validate != null) {
                    fkConstraint.setValidateForeignKey(constraints.getValidateForeignKey());
                }
                statement.addColumnConstraint(fkConstraint);
            }
            if ((constraints.isUnique() != null) && constraints.isUnique()) {
                statement.addColumnConstraint(new UniqueConstraint(constraints.getUniqueConstraintName(), constraints.getValidateUnique() == null ? true : constraints.getValidateUnique()).addColumns(column.getName()));
            }
        }
        if (isAutoIncrement) {
            statement.addColumnConstraint(new AutoIncrementConstraint(column.getName(), column.getStartWith(), column.getIncrementBy(), column.getGenerationType(), column.getDefaultOnNull()));
        }
    }
    statement.setTablespace(StringUtil.trimToNull(getTablespace()));
    List<SqlStatement> statements = new ArrayList<>();
    statements.add(statement);
    if (StringUtil.trimToNull(remarks) != null) {
        SetTableRemarksStatement remarksStatement = new SetTableRemarksStatement(catalogName, schemaName, tableName, remarks);
        if (SqlGeneratorFactory.getInstance().supports(remarksStatement, database)) {
            statements.add(remarksStatement);
        }
    }
    for (ColumnConfig column : getColumns()) {
        String columnRemarks = StringUtil.trimToNull(column.getRemarks());
        if (columnRemarks != null) {
            SetColumnRemarksStatement remarksStatement = new SetColumnRemarksStatement(catalogName, schemaName, tableName, column.getName(), columnRemarks, column.getType());
            if (SqlGeneratorFactory.getInstance().supports(remarksStatement, database)) {
                statements.add(remarksStatement);
            }
        }
        final Boolean computed = column.getComputed();
        if (computed != null && computed) {
            statement.setComputed(column.getName());
        }
    }
    return statements.toArray(new SqlStatement[statements.size()]);
}
Also used : CreateTableStatement(liquibase.statement.core.CreateTableStatement) LiquibaseDataType(liquibase.datatype.LiquibaseDataType) SetTableRemarksStatement(liquibase.statement.core.SetTableRemarksStatement) ArrayList(java.util.ArrayList) UnexpectedLiquibaseException(liquibase.exception.UnexpectedLiquibaseException) SetColumnRemarksStatement(liquibase.statement.core.SetColumnRemarksStatement)

Example 7 with LiquibaseDataType

use of liquibase.datatype.LiquibaseDataType in project liquibase by liquibase.

the class SqlUtil method parseValue.

public static Object parseValue(Database database, Object val, DataType type) {
    if (!(val instanceof String)) {
        return val;
    }
    int typeId = Integer.MIN_VALUE;
    if (type.getDataTypeId() != null) {
        typeId = type.getDataTypeId();
    }
    LiquibaseDataType liquibaseDataType = DataTypeFactory.getInstance().from(type, database);
    String stringVal = (String) val;
    if (stringVal.isEmpty()) {
        if (liquibaseDataType instanceof CharType) {
            return "";
        } else {
            return null;
        }
    }
    if ((database instanceof OracleDatabase) && !stringVal.startsWith("'") && !stringVal.endsWith("'")) {
        // oracle returns functions without quotes
        Object maybeDate = null;
        if ((liquibaseDataType instanceof DateType) || (typeId == Types.DATE)) {
            if (stringVal.endsWith("'HH24:MI:SS')")) {
                maybeDate = DataTypeFactory.getInstance().fromDescription("time", database).sqlToObject(stringVal, database);
            } else {
                maybeDate = DataTypeFactory.getInstance().fromDescription("date", database).sqlToObject(stringVal, database);
            }
        } else if ((liquibaseDataType instanceof DateTimeType) || (typeId == Types.TIMESTAMP)) {
            maybeDate = DataTypeFactory.getInstance().fromDescription("datetime", database).sqlToObject(stringVal, database);
        } else if (!stringVal.matches("\\d+\\.?\\d*")) {
            // not just a number
            return new DatabaseFunction(stringVal);
        }
        if (maybeDate != null) {
            if (maybeDate instanceof java.util.Date) {
                return maybeDate;
            } else {
                return new DatabaseFunction(stringVal);
            }
        }
    }
    boolean strippedSingleQuotes = false;
    if (stringVal.startsWith("'") && stringVal.endsWith("'")) {
        stringVal = stringVal.substring(1, stringVal.length() - 1);
        strippedSingleQuotes = true;
    } else if (stringVal.startsWith("((") && stringVal.endsWith("))")) {
        stringVal = stringVal.substring(2, stringVal.length() - 2);
    } else if (stringVal.startsWith("('") && stringVal.endsWith("')")) {
        stringVal = stringVal.substring(2, stringVal.length() - 2);
    } else if (stringVal.startsWith("(") && stringVal.endsWith(")")) {
        return new DatabaseFunction(stringVal.substring(1, stringVal.length() - 1));
    }
    String typeName = type.getTypeName();
    try (Scanner scanner = new Scanner(stringVal.trim())) {
        if (typeId == Types.ARRAY) {
            return new DatabaseFunction(stringVal);
        } else if ((liquibaseDataType instanceof BigIntType || typeId == Types.BIGINT)) {
            if (scanner.hasNextBigInteger()) {
                return scanner.nextBigInteger();
            } else {
                return new DatabaseFunction(stringVal);
            }
        } else if (typeId == Types.BINARY) {
            return new DatabaseFunction(stringVal.trim());
        } else if (typeId == Types.BIT) {
            if (stringVal.startsWith("b'") || stringVal.startsWith("B'")) {
                // mysql returns boolean values as b'0' and b'1'
                stringVal = stringVal.replaceFirst("b'", "").replaceFirst("B'", "").replaceFirst("'$", "");
            }
            // postgres defaults for bit columns look like: B'0'::"bit"
            if (stringVal.endsWith("'::\"bit\"")) {
                stringVal = stringVal.replaceFirst("'::\"bit\"", "");
            }
            stringVal = stringVal.trim();
            if (database instanceof MySQLDatabase) {
                return "1".equals(stringVal) || "true".equalsIgnoreCase(stringVal);
            }
            Object value = stringVal;
            if (scanner.hasNextBoolean()) {
                value = scanner.nextBoolean();
            } else if (scanner.hasNextInt()) {
                value = Integer.valueOf(stringVal);
            }
            // Make sure we handle BooleanType values which are not Boolean
            if (database instanceof MSSQLDatabase) {
                if (value instanceof Boolean) {
                    if ((Boolean) value) {
                        return new DatabaseFunction("'true'");
                    } else {
                        return new DatabaseFunction("'false'");
                    }
                } else if (value instanceof Integer) {
                    if (((Integer) value) != 0) {
                        return new DatabaseFunction("'true'");
                    } else {
                        return new DatabaseFunction("'false'");
                    }
                } else {
                    // you can declare in MsSQL: `col_name bit default 'nonsense'`
                    return new DatabaseFunction(String.format("'%s'", value));
                }
            }
            return value;
        } else if (liquibaseDataType instanceof BlobType || typeId == Types.BLOB) {
            if (strippedSingleQuotes) {
                return stringVal;
            } else {
                return new DatabaseFunction(stringVal);
            }
        } else if ((liquibaseDataType instanceof BooleanType || typeId == Types.BOOLEAN)) {
            if (scanner.hasNextBoolean()) {
                return scanner.nextBoolean();
            } else {
                return new DatabaseFunction(stringVal);
            }
        } else if (liquibaseDataType instanceof CharType || typeId == Types.CHAR) {
            return stringVal;
        } else if (liquibaseDataType instanceof ClobType || typeId == Types.CLOB) {
            return stringVal;
        } else if (typeId == Types.DATALINK) {
            return new DatabaseFunction(stringVal);
        } else if (liquibaseDataType instanceof DateType || typeId == Types.DATE) {
            if (typeName.equalsIgnoreCase("year")) {
                return stringVal.trim();
            }
            return DataTypeFactory.getInstance().fromDescription("date", database).sqlToObject(stringVal, database);
        } else if ((liquibaseDataType instanceof DecimalType || typeId == Types.DECIMAL)) {
            if (scanner.hasNextBigDecimal()) {
                return scanner.nextBigDecimal();
            } else {
                return new DatabaseFunction(stringVal);
            }
        } else if (typeId == Types.DISTINCT) {
            return new DatabaseFunction(stringVal);
        } else if ((liquibaseDataType instanceof DoubleType || typeId == Types.DOUBLE)) {
            if (scanner.hasNextDouble()) {
                return scanner.nextDouble();
            } else {
                return new DatabaseFunction(stringVal);
            }
        } else if ((liquibaseDataType instanceof FloatType || typeId == Types.FLOAT)) {
            if (scanner.hasNextFloat()) {
                return scanner.nextFloat();
            } else {
                return new DatabaseFunction(stringVal);
            }
        } else if ((liquibaseDataType instanceof IntType || typeId == Types.INTEGER)) {
            if (scanner.hasNextInt()) {
                return scanner.nextInt();
            } else {
                return new DatabaseFunction(stringVal);
            }
        } else if (typeId == Types.JAVA_OBJECT) {
            return new DatabaseFunction(stringVal);
        } else if (typeId == Types.LONGNVARCHAR) {
            return stringVal;
        } else if (typeId == Types.LONGVARBINARY) {
            return new DatabaseFunction(stringVal);
        } else if (typeId == Types.LONGVARCHAR) {
            return stringVal;
        } else if (liquibaseDataType instanceof NCharType || typeId == Types.NCHAR || liquibaseDataType.getName().equalsIgnoreCase("NCLOB")) {
            return stringVal;
        } else if (typeId == Types.NCLOB) {
            return stringVal;
        } else if (typeId == Types.NULL) {
            return null;
        } else if ((liquibaseDataType instanceof NumberType || typeId == Types.NUMERIC)) {
            if (scanner.hasNextBigDecimal()) {
                if (database instanceof MSSQLDatabase && stringVal.endsWith(".0") || stringVal.endsWith(".00") || stringVal.endsWith(".000")) {
                    // MSSQL can store the value with the decimal digits. return it directly to avoid unexpected differences
                    return new DatabaseFunction(stringVal);
                }
                return scanner.nextBigDecimal();
            } else {
                if (stringVal.equals("")) {
                    // can have numeric default '' on sql server
                    return new DatabaseFunction("''");
                }
                return new DatabaseFunction(stringVal);
            }
        } else if (liquibaseDataType instanceof NVarcharType || typeId == Types.NVARCHAR) {
            return stringVal;
        } else if (typeId == Types.OTHER) {
            if (database instanceof AbstractDb2Database && typeName.equalsIgnoreCase("DECFLOAT")) {
                return new BigDecimal(stringVal);
            }
            return new DatabaseFunction(stringVal);
        } else if (typeId == Types.REAL) {
            return new BigDecimal(stringVal.trim());
        } else if (typeId == Types.REF) {
            return new DatabaseFunction(stringVal);
        } else if (typeId == Types.ROWID) {
            return new DatabaseFunction(stringVal);
        } else if ((liquibaseDataType instanceof SmallIntType || typeId == Types.SMALLINT)) {
            if (scanner.hasNextInt()) {
                return scanner.nextInt();
            } else {
                return new DatabaseFunction(stringVal);
            }
        } else if (typeId == Types.SQLXML) {
            return new DatabaseFunction(stringVal);
        } else if (typeId == Types.STRUCT) {
            return new DatabaseFunction(stringVal);
        } else if (liquibaseDataType instanceof TimeType || typeId == Types.TIME) {
            return DataTypeFactory.getInstance().fromDescription("time", database).sqlToObject(stringVal, database);
        } else if (liquibaseDataType instanceof DateTimeType || liquibaseDataType instanceof TimestampType || typeId == Types.TIMESTAMP) {
            return DataTypeFactory.getInstance().fromDescription("datetime", database).sqlToObject(stringVal, database);
        } else if ((liquibaseDataType instanceof TinyIntType || typeId == Types.TINYINT)) {
            if (scanner.hasNextInt()) {
                return scanner.nextInt();
            } else {
                return new DatabaseFunction(stringVal);
            }
        } else if (typeId == Types.VARBINARY) {
            return new DatabaseFunction(stringVal);
        } else if (liquibaseDataType instanceof VarcharType || typeId == Types.VARCHAR) {
            return stringVal;
        } else if (database instanceof MySQLDatabase && typeName.toLowerCase().startsWith("enum")) {
            return stringVal;
        } else if ((database instanceof MSSQLDatabase) && typeName.toLowerCase().startsWith("datetimeoffset")) {
            return stringVal;
        } else {
            if (stringVal.equals("")) {
                return stringVal;
            }
            Scope.getCurrentScope().getLog(SqlUtil.class).info("Unknown default value: value '" + stringVal + "' type " + typeName + " (" + type + "). Calling it a function so it's not additionally quoted");
            if (strippedSingleQuotes) {
                // put quotes back
                return new DatabaseFunction("'" + stringVal + "'");
            }
            return new DatabaseFunction(stringVal);
        }
    }
}
Also used : Scanner(java.util.Scanner) DatabaseFunction(liquibase.statement.DatabaseFunction) AbstractDb2Database(liquibase.database.core.AbstractDb2Database) MSSQLDatabase(liquibase.database.core.MSSQLDatabase) LiquibaseDataType(liquibase.datatype.LiquibaseDataType) MySQLDatabase(liquibase.database.core.MySQLDatabase) BigDecimal(java.math.BigDecimal) OracleDatabase(liquibase.database.core.OracleDatabase)

Example 8 with LiquibaseDataType

use of liquibase.datatype.LiquibaseDataType in project liquibase by liquibase.

the class CreateTableGeneratorTest method combineUniqueConstraints.

@Test
public void combineUniqueConstraints() {
    Database database = new SQLiteDatabase();
    database.setOutputDefaultSchema(true);
    LiquibaseDataType integerType = DataTypeFactory.getInstance().fromDescription("INTEGER", database);
    CreateTableStatement statement = new CreateTableStatement(CATALOG_NAME, SCHEMA_NAME, TABLE_NAME);
    statement.addColumn("MY_KEY", integerType, new UniqueConstraint("SAME"));
    statement.addColumn("MY_OTHER_KEY", integerType, new UniqueConstraint("SAME"));
    statement.addColumn("SINGLE_UNIQUE_KEY", integerType, new UniqueConstraint("DIFFERENT"));
    statement.addColumn("UNIQUE_NO_CONSTRAINT_NAME", integerType, new UniqueConstraint());
    Sql[] generatedSql = this.generatorUnderTest.generateSql(statement, database, null);
    String expectedSql = "CREATE TABLE CATALOG_NAME.TABLE_NAME " + "(MY_KEY INTEGER, MY_OTHER_KEY INTEGER, " + "SINGLE_UNIQUE_KEY INTEGER, UNIQUE_NO_CONSTRAINT_NAME INTEGER, " + "UNIQUE (UNIQUE_NO_CONSTRAINT_NAME), " + "CONSTRAINT SAME UNIQUE (MY_KEY, MY_OTHER_KEY), " + "CONSTRAINT DIFFERENT UNIQUE (SINGLE_UNIQUE_KEY))";
    assertEquals(expectedSql, generatedSql[0].toSql());
}
Also used : SQLiteDatabase(liquibase.database.core.SQLiteDatabase) LiquibaseDataType(liquibase.datatype.LiquibaseDataType) CreateTableStatement(liquibase.statement.core.CreateTableStatement) SQLiteDatabase(liquibase.database.core.SQLiteDatabase) DerbyDatabase(liquibase.database.core.DerbyDatabase) H2Database(liquibase.database.core.H2Database) MSSQLDatabase(liquibase.database.core.MSSQLDatabase) MySQLDatabase(liquibase.database.core.MySQLDatabase) PostgresDatabase(liquibase.database.core.PostgresDatabase) OracleDatabase(liquibase.database.core.OracleDatabase) SybaseDatabase(liquibase.database.core.SybaseDatabase) SybaseASADatabase(liquibase.database.core.SybaseASADatabase) Database(liquibase.database.Database) AbstractDb2Database(liquibase.database.core.AbstractDb2Database) HsqlDatabase(liquibase.database.core.HsqlDatabase) Sql(liquibase.sql.Sql) AbstractSqlGeneratorTest(liquibase.sqlgenerator.AbstractSqlGeneratorTest) Test(org.junit.Test)

Example 9 with LiquibaseDataType

use of liquibase.datatype.LiquibaseDataType 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 10 with LiquibaseDataType

use of liquibase.datatype.LiquibaseDataType in project liquibase by liquibase.

the class MissingTableChangeGenerator method fixMissing.

@Override
public Change[] fixMissing(DatabaseObject missingObject, DiffOutputControl control, Database referenceDatabase, Database comparisonDatabase, ChangeGeneratorChain chain) {
    Table missingTable = (Table) missingObject;
    PrimaryKey primaryKey = missingTable.getPrimaryKey();
    List<String> pkColumnList = ((primaryKey != null) ? primaryKey.getColumnNamesAsList() : null);
    Map<Column, UniqueConstraint> singleUniqueConstraints = getSingleColumnUniqueConstraints(missingTable);
    CreateTableChange change = createCreateTableChange();
    change.setTableName(missingTable.getName());
    if (control.getIncludeCatalog()) {
        change.setCatalogName(missingTable.getSchema().getCatalogName());
    }
    if (control.getIncludeSchema()) {
        change.setSchemaName(missingTable.getSchema().getName());
    }
    if (missingTable.getRemarks() != null) {
        change.setRemarks(missingTable.getRemarks());
    }
    if (control.getIncludeTablespace() && (missingTable.getTablespace() != null) && comparisonDatabase.supportsTablespaces()) {
        change.setTablespace(missingTable.getTablespace());
    }
    for (Column column : missingTable.getColumns()) {
        ColumnConfig columnConfig = new ColumnConfig();
        columnConfig.setName(column.getName());
        LiquibaseDataType ldt = DataTypeFactory.getInstance().from(column.getType(), referenceDatabase);
        DatabaseDataType ddt = ldt.toDatabaseDataType(comparisonDatabase);
        String typeString = ddt.toString();
        if (comparisonDatabase instanceof MSSQLDatabase) {
            typeString = comparisonDatabase.unescapeDataTypeString(typeString);
        }
        columnConfig.setType(typeString);
        if (column.isAutoIncrement()) {
            columnConfig.setAutoIncrement(true);
        }
        boolean primaryKeyOrderMatchesTableOrder = checkPrimaryKeyOrderMatchesTableOrder(missingTable, pkColumnList);
        ConstraintsConfig constraintsConfig = null;
        // In MySQL, the primary key must be specified at creation for an autoincrement column
        if ((pkColumnList != null) && primaryKeyOrderMatchesTableOrder && pkColumnList.contains(column.getName())) {
            if ((referenceDatabase instanceof MSSQLDatabase) && (primaryKey.getBackingIndex() != null) && (primaryKey.getBackingIndex().getClustered() != null) && !primaryKey.getBackingIndex().getClustered()) {
            // have to handle PK as a separate statement
            } else if ((referenceDatabase instanceof PostgresDatabase) && (primaryKey.getBackingIndex() != null) && (primaryKey.getBackingIndex().getClustered() != null) && primaryKey.getBackingIndex().getClustered()) {
            // have to handle PK as a separate statement
            } else {
                constraintsConfig = new ConstraintsConfig();
                if (shouldAddPrimarykeyToConstraints(missingObject, control, referenceDatabase, comparisonDatabase)) {
                    constraintsConfig.setPrimaryKey(true);
                    constraintsConfig.setPrimaryKeyTablespace(primaryKey.getTablespace());
                    // MySQL sets some primary key names as PRIMARY which is invalid
                    if ((comparisonDatabase instanceof MySQLDatabase) && "PRIMARY".equals(primaryKey.getName())) {
                        constraintsConfig.setPrimaryKeyName(null);
                    } else {
                        constraintsConfig.setPrimaryKeyName(primaryKey.getName());
                    }
                    control.setAlreadyHandledMissing(primaryKey);
                    control.setAlreadyHandledMissing(primaryKey.getBackingIndex());
                } else {
                    constraintsConfig.setNullable(false);
                }
            }
        }
        if ((column.isNullable() != null) && !column.isNullable()) {
            if (constraintsConfig == null) {
                constraintsConfig = new ConstraintsConfig();
            }
            constraintsConfig.setNullable(false);
            if (!column.getValidateNullable()) {
                constraintsConfig.setValidateNullable(false);
            }
            constraintsConfig.setNotNullConstraintName(column.getAttribute("notNullConstraintName", String.class));
        }
        if (referenceDatabase instanceof MySQLDatabase) {
            UniqueConstraint uniqueConstraint = singleUniqueConstraints.get(column);
            if (uniqueConstraint != null) {
                if (!control.alreadyHandledMissing(uniqueConstraint, referenceDatabase)) {
                    if (constraintsConfig == null) {
                        constraintsConfig = new ConstraintsConfig();
                    }
                    constraintsConfig.setUnique(true);
                    control.setAlreadyHandledMissing(uniqueConstraint);
                    control.setAlreadyHandledMissing(uniqueConstraint.getBackingIndex());
                }
            }
        }
        if (constraintsConfig != null) {
            columnConfig.setConstraints(constraintsConfig);
        }
        setDefaultValue(columnConfig, column, referenceDatabase);
        if (column.getRemarks() != null) {
            columnConfig.setRemarks(column.getRemarks());
        }
        Column.AutoIncrementInformation autoIncrementInfo = column.getAutoIncrementInformation();
        if (autoIncrementInfo != null) {
            BigInteger startWith = autoIncrementInfo.getStartWith();
            BigInteger incrementBy = autoIncrementInfo.getIncrementBy();
            String generationType = autoIncrementInfo.getGenerationType();
            Boolean defaultOnNull = autoIncrementInfo.getDefaultOnNull();
            if ((startWith != null) && !startWith.equals(BigInteger.ONE)) {
                columnConfig.setStartWith(startWith);
            }
            if ((incrementBy != null) && !incrementBy.equals(BigInteger.ONE)) {
                columnConfig.setIncrementBy(incrementBy);
            }
            if (StringUtil.isNotEmpty(generationType)) {
                columnConfig.setGenerationType(generationType);
                if (defaultOnNull != null) {
                    columnConfig.setDefaultOnNull(defaultOnNull);
                }
            }
        }
        // 
        if (column.getComputed() != null) {
            columnConfig.setComputed(column.getComputed());
        }
        change.addColumn(columnConfig);
        control.setAlreadyHandledMissing(column);
    }
    return new Change[] { change };
}
Also used : Table(liquibase.structure.core.Table) ColumnConfig(liquibase.change.ColumnConfig) LiquibaseDataType(liquibase.datatype.LiquibaseDataType) PrimaryKey(liquibase.structure.core.PrimaryKey) UniqueConstraint(liquibase.structure.core.UniqueConstraint) MySQLDatabase(liquibase.database.core.MySQLDatabase) Change(liquibase.change.Change) CreateTableChange(liquibase.change.core.CreateTableChange) PostgresDatabase(liquibase.database.core.PostgresDatabase) DatabaseDataType(liquibase.datatype.DatabaseDataType) Column(liquibase.structure.core.Column) CreateTableChange(liquibase.change.core.CreateTableChange) ConstraintsConfig(liquibase.change.ConstraintsConfig) BigInteger(java.math.BigInteger) MSSQLDatabase(liquibase.database.core.MSSQLDatabase)

Aggregations

LiquibaseDataType (liquibase.datatype.LiquibaseDataType)12 DatabaseFunction (liquibase.statement.DatabaseFunction)5 PostgresDatabase (liquibase.database.core.PostgresDatabase)4 BooleanType (liquibase.datatype.core.BooleanType)4 ArrayList (java.util.ArrayList)3 ColumnConfig (liquibase.change.ColumnConfig)3 MSSQLDatabase (liquibase.database.core.MSSQLDatabase)3 MySQLDatabase (liquibase.database.core.MySQLDatabase)3 SQLiteDatabase (liquibase.database.core.SQLiteDatabase)3 Column (liquibase.structure.core.Column)3 BigDecimal (java.math.BigDecimal)2 BigInteger (java.math.BigInteger)2 Date (java.util.Date)2 Change (liquibase.change.Change)2 AbstractDb2Database (liquibase.database.core.AbstractDb2Database)2 HsqlDatabase (liquibase.database.core.HsqlDatabase)2 OracleDatabase (liquibase.database.core.OracleDatabase)2 CharType (liquibase.datatype.core.CharType)2 Difference (liquibase.diff.Difference)2 UnexpectedLiquibaseException (liquibase.exception.UnexpectedLiquibaseException)2