Search in sources :

Example 1 with ColumnConfig

use of liquibase.change.ColumnConfig in project liquibase by liquibase.

the class LoadDataChange method generateStatements.

@Override
public SqlStatement[] generateStatements(Database database) {
    CSVReader reader = null;
    try {
        reader = getCSVReader();
        if (reader == null) {
            throw new UnexpectedLiquibaseException("Unable to read file " + this.getFile());
        }
        String[] headers = reader.readNext();
        if (headers == null) {
            throw new UnexpectedLiquibaseException("Data file " + getFile() + " was empty");
        }
        List<SqlStatement> statements = new ArrayList<SqlStatement>();
        boolean anyPreparedStatements = false;
        String[] line;
        // Start at '1' to take into account the header (already processed)
        int lineNumber = 1;
        boolean isCommentingEnabled = StringUtils.isNotEmpty(commentLineStartsWith);
        while ((line = reader.readNext()) != null) {
            lineNumber++;
            if (line.length == 0 || (line.length == 1 && StringUtils.trimToNull(line[0]) == null) || (isCommentingEnabled && isLineCommented(line))) {
                //nothing on this line
                continue;
            }
            // (Failure could indicate unquoted strings with commas, for example).
            if (line.length != headers.length) {
                throw new UnexpectedLiquibaseException("CSV file " + getFile() + " Line " + lineNumber + " has " + line.length + " values defined, Header has " + headers.length + ". Numbers MUST be equal (check for unquoted string with embedded commas)");
            }
            boolean needsPreparedStatement = false;
            List<ColumnConfig> columns = new ArrayList<ColumnConfig>();
            for (int i = 0; i < headers.length; i++) {
                Object value = line[i];
                String columnName = headers[i].trim();
                ColumnConfig valueConfig = new ColumnConfig();
                ColumnConfig columnConfig = getColumnConfig(i, headers[i].trim());
                if (columnConfig != null) {
                    if ("skip".equalsIgnoreCase(columnConfig.getType())) {
                        continue;
                    }
                    // don't overwrite header name unless there is actually a value to override it with
                    if (columnConfig.getName() != null) {
                        columnName = columnConfig.getName();
                    }
                    valueConfig.setName(columnName);
                    if (columnConfig.getType() != null) {
                        if (columnConfig.getType().equalsIgnoreCase("BOOLEAN")) {
                            if (value.toString().equalsIgnoreCase("NULL")) {
                                valueConfig.setValue(null);
                            } else {
                                valueConfig.setValueBoolean(BooleanParser.parseBoolean(value.toString().toLowerCase()));
                            }
                        } else if (columnConfig.getType().equalsIgnoreCase("NUMERIC")) {
                            if (value.toString().equalsIgnoreCase("NULL")) {
                                valueConfig.setValue(null);
                            } else {
                                valueConfig.setValueNumeric(value.toString());
                            }
                        } else if (columnConfig.getType().toLowerCase().contains("date") || columnConfig.getType().toLowerCase().contains("time")) {
                            if (value.toString().equalsIgnoreCase("NULL")) {
                                valueConfig.setValue(null);
                            } else {
                                valueConfig.setValueDate(value.toString());
                            }
                        } else if (columnConfig.getType().equalsIgnoreCase("STRING")) {
                            if (value.toString().equalsIgnoreCase("NULL")) {
                                valueConfig.setValue(null);
                            } else {
                                valueConfig.setValue(value.toString());
                            }
                        } else if (columnConfig.getType().equalsIgnoreCase("COMPUTED")) {
                            if (value.toString().equalsIgnoreCase("NULL")) {
                                valueConfig.setValue(null);
                            } else {
                                liquibase.statement.DatabaseFunction function = new liquibase.statement.DatabaseFunction(value.toString());
                                valueConfig.setValueComputed(function);
                            }
                        } else if (columnConfig.getType().equalsIgnoreCase("SEQUENCE")) {
                            String sequenceName;
                            if (value.toString().equalsIgnoreCase("NULL")) {
                                sequenceName = columnConfig.getDefaultValue();
                                if (sequenceName == null) {
                                    throw new UnexpectedLiquibaseException("Must set a sequence name in the loadData column defaultValue attribute");
                                }
                            } else {
                                sequenceName = value.toString();
                            }
                            liquibase.statement.SequenceNextValueFunction function = new liquibase.statement.SequenceNextValueFunction(sequenceName);
                            valueConfig.setValueComputed(function);
                        } else if (columnConfig.getType().equalsIgnoreCase("BLOB")) {
                            if (value.toString().equalsIgnoreCase("NULL")) {
                                valueConfig.setValue(null);
                            } else {
                                valueConfig.setValueBlobFile(value.toString());
                                needsPreparedStatement = true;
                            }
                        } else if (columnConfig.getType().equalsIgnoreCase("CLOB")) {
                            if (value.toString().equalsIgnoreCase("NULL")) {
                                valueConfig.setValue(null);
                            } else {
                                valueConfig.setValueClobFile(value.toString());
                                needsPreparedStatement = true;
                            }
                        } else {
                            throw new UnexpectedLiquibaseException("loadData type of " + columnConfig.getType() + " is not supported.  Please use BOOLEAN, NUMERIC, DATE, STRING, COMPUTED, SEQUENCE or SKIP");
                        }
                    }
                } else {
                    if (columnName.contains("(") || columnName.contains(")") && database instanceof AbstractJdbcDatabase) {
                        columnName = ((AbstractJdbcDatabase) database).quoteObject(columnName, Column.class);
                    }
                    valueConfig.setName(columnName);
                    if (value == null || value.toString().equalsIgnoreCase("NULL")) {
                        // value is always going to be a string unless overridden by ColumnConfig
                        valueConfig.setValue((String) value);
                    } else {
                        valueConfig.setValue(value.toString());
                    }
                }
                columns.add(valueConfig);
            }
            if (needsPreparedStatement) {
                anyPreparedStatements = true;
                statements.add(new InsertExecutablePreparedStatement(database, getCatalogName(), getSchemaName(), getTableName(), columns, getChangeSet(), getResourceAccessor()));
            } else {
                InsertStatement insertStatement = this.createStatement(getCatalogName(), getSchemaName(), getTableName());
                for (ColumnConfig column : columns) {
                    String columnName = column.getName();
                    Object value = column.getValueObject();
                    if (value == null) {
                        value = "NULL";
                    }
                    insertStatement.addColumnValue(columnName, value);
                }
                statements.add(insertStatement);
            }
        }
        if (anyPreparedStatements) {
            return statements.toArray(new SqlStatement[statements.size()]);
        } else {
            InsertSetStatement statementSet = this.createStatementSet(getCatalogName(), getSchemaName(), getTableName());
            for (SqlStatement stmt : statements) {
                statementSet.addInsertStatement((InsertStatement) stmt);
            }
            if (database instanceof MSSQLDatabase || database instanceof MySQLDatabase || database instanceof PostgresDatabase) {
                List<InsertStatement> innerStatements = statementSet.getStatements();
                if (innerStatements != null && innerStatements.size() > 0 && innerStatements.get(0) instanceof InsertOrUpdateStatement) {
                    //cannot do insert or update in a single statement
                    return statementSet.getStatementsArray();
                }
                // we only return a single "statement" - it's capable of emitting multiple sub-statements, should the need arise, on generation.
                return new SqlStatement[] { statementSet };
            } else {
                return statementSet.getStatementsArray();
            }
        }
    } catch (IOException e) {
        throw new RuntimeException(e);
    } catch (UnexpectedLiquibaseException ule) {
        if (getChangeSet() != null && getChangeSet().getFailOnError() != null && !getChangeSet().getFailOnError()) {
            Logger log = LogFactory.getLogger();
            log.info("Change set " + getChangeSet().toString(false) + " failed, but failOnError was false.  Error: " + ule.getMessage());
            return new SqlStatement[0];
        } else {
            throw ule;
        }
    } finally {
        if (null != reader) {
            try {
                reader.close();
            } catch (IOException e) {
                ;
            }
        }
    }
}
Also used : InsertOrUpdateStatement(liquibase.statement.core.InsertOrUpdateStatement) ColumnConfig(liquibase.change.ColumnConfig) Logger(liquibase.logging.Logger) InsertStatement(liquibase.statement.core.InsertStatement) SqlStatement(liquibase.statement.SqlStatement) Column(liquibase.structure.core.Column) MSSQLDatabase(liquibase.database.core.MSSQLDatabase) InsertExecutablePreparedStatement(liquibase.statement.InsertExecutablePreparedStatement) CSVReader(liquibase.util.csv.CSVReader) MySQLDatabase(liquibase.database.core.MySQLDatabase) IOException(java.io.IOException) AbstractJdbcDatabase(liquibase.database.AbstractJdbcDatabase) PostgresDatabase(liquibase.database.core.PostgresDatabase) InsertSetStatement(liquibase.statement.core.InsertSetStatement) UnexpectedLiquibaseException(liquibase.exception.UnexpectedLiquibaseException)

Example 2 with ColumnConfig

use of liquibase.change.ColumnConfig in project liquibase by liquibase.

the class MissingDataChangeGenerator method fixMissing.

@Override
public Change[] fixMissing(DatabaseObject missingObject, DiffOutputControl outputControl, Database referenceDatabase, Database comparisionDatabase, ChangeGeneratorChain chain) {
    Statement stmt = null;
    ResultSet rs = null;
    try {
        Data data = (Data) missingObject;
        Table table = data.getTable();
        if (referenceDatabase.isLiquibaseObject(table)) {
            return null;
        }
        String sql = "SELECT * FROM " + referenceDatabase.escapeTableName(table.getSchema().getCatalogName(), table.getSchema().getName(), table.getName());
        stmt = ((JdbcConnection) referenceDatabase.getConnection()).createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
        stmt.setFetchSize(1000);
        rs = stmt.executeQuery(sql);
        List<String> columnNames = new ArrayList<String>();
        for (int i = 0; i < rs.getMetaData().getColumnCount(); i++) {
            columnNames.add(rs.getMetaData().getColumnName(i + 1));
        }
        List<Change> changes = new ArrayList<Change>();
        while (rs.next()) {
            InsertDataChange change = new InsertDataChange();
            if (outputControl.getIncludeCatalog()) {
                change.setCatalogName(table.getSchema().getCatalogName());
            }
            if (outputControl.getIncludeSchema()) {
                change.setSchemaName(table.getSchema().getName());
            }
            change.setTableName(table.getName());
            // loop over all columns for this row
            for (int i = 0; i < columnNames.size(); i++) {
                ColumnConfig column = new ColumnConfig();
                column.setName(columnNames.get(i));
                Object value = JdbcUtils.getResultSetValue(rs, i + 1);
                if (value == null) {
                    column.setValue(null);
                } else if (value instanceof Number) {
                    column.setValueNumeric((Number) value);
                } else if (value instanceof Boolean) {
                    column.setValueBoolean((Boolean) value);
                } else if (value instanceof Date) {
                    column.setValueDate((Date) value);
                } else if (value instanceof byte[]) {
                    if (referenceDatabase instanceof InformixDatabase) {
                        column.setValue(new String((byte[]) value, LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getOutputEncoding()));
                    }
                    column.setValueComputed(new DatabaseFunction("UNSUPPORTED FOR DIFF: BINARY DATA"));
                } else {
                    // fall back to simple string
                    column.setValue(value.toString().replace("\\", "\\\\"));
                }
                change.addColumn(column);
            }
            // for each row, add a new change
            // (there will be one group per table)
            changes.add(change);
        }
        return changes.toArray(new Change[changes.size()]);
    } catch (Exception e) {
        throw new UnexpectedLiquibaseException(e);
    } finally {
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException ignore) {
            }
        }
        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException ignore) {
            }
        }
    }
}
Also used : GlobalConfiguration(liquibase.configuration.GlobalConfiguration) ColumnConfig(liquibase.change.ColumnConfig) DatabaseFunction(liquibase.statement.DatabaseFunction) ArrayList(java.util.ArrayList) InsertDataChange(liquibase.change.core.InsertDataChange) Change(liquibase.change.Change) Date(java.util.Date) UnexpectedLiquibaseException(liquibase.exception.UnexpectedLiquibaseException) InsertDataChange(liquibase.change.core.InsertDataChange) InformixDatabase(liquibase.database.core.InformixDatabase) DatabaseObject(liquibase.structure.DatabaseObject) UnexpectedLiquibaseException(liquibase.exception.UnexpectedLiquibaseException)

Example 3 with ColumnConfig

use of liquibase.change.ColumnConfig in project liquibase by liquibase.

the class AddColumnGeneratorSQLite method generateSql.

@Override
public Sql[] generateSql(final AddColumnStatement statement, Database database, SqlGeneratorChain sqlGeneratorChain) {
    // SQLite does not support this ALTER TABLE operation until now.
    // For more information see: http://www.sqlite.org/omitted.html.
    // This is a small work around...
    List<Sql> sql = new ArrayList<Sql>();
    // define alter table logic
    SQLiteDatabase.AlterTableVisitor rename_alter_visitor = new SQLiteDatabase.AlterTableVisitor() {

        public ColumnConfig[] getColumnsToAdd() {
            return new ColumnConfig[] { new ColumnConfig().setName(statement.getColumnName()).setType(statement.getColumnType()).setAutoIncrement(statement.isAutoIncrement()) };
        }

        public boolean copyThisColumn(ColumnConfig column) {
            return !column.getName().equals(statement.getColumnName());
        }

        public boolean createThisColumn(ColumnConfig column) {
            return true;
        }

        public boolean createThisIndex(Index index) {
            return true;
        }
    };
    try {
        // alter table
        List<SqlStatement> alterTableStatements = SQLiteDatabase.getAlterTableStatements(rename_alter_visitor, database, statement.getCatalogName(), statement.getSchemaName(), statement.getTableName());
        sql.addAll(Arrays.asList(SqlGeneratorFactory.getInstance().generateSql(alterTableStatements.toArray(new SqlStatement[alterTableStatements.size()]), database)));
    } catch (DatabaseException e) {
        System.err.println(e);
        e.printStackTrace();
    }
    return sql.toArray(new Sql[sql.size()]);
}
Also used : SqlStatement(liquibase.statement.SqlStatement) ColumnConfig(liquibase.change.ColumnConfig) SQLiteDatabase(liquibase.database.core.SQLiteDatabase) ArrayList(java.util.ArrayList) Index(liquibase.structure.core.Index) DatabaseException(liquibase.exception.DatabaseException) Sql(liquibase.sql.Sql) UnparsedSql(liquibase.sql.UnparsedSql)

Example 4 with ColumnConfig

use of liquibase.change.ColumnConfig in project liquibase by liquibase.

the class ExecutablePreparedStatementBase method execute.

@Override
public void execute(PreparedStatementFactory factory) throws DatabaseException {
    // build the sql statement
    List<ColumnConfig> cols = new ArrayList<ColumnConfig>(getColumns().size());
    String sql = generateSql(cols);
    log.info("Prepared statement: " + sql);
    log.debug("Number of columns = " + cols.size());
    // create prepared statement
    PreparedStatement stmt = factory.create(sql);
    try {
        // attach params
        // index starts from 1
        int i = 1;
        for (ColumnConfig col : cols) {
            log.debug("Applying column parameter = " + i + " for column " + col.getName());
            applyColumnParameter(stmt, i, col);
            i++;
        }
        // trigger execution
        stmt.execute();
    } catch (SQLException e) {
        throw new DatabaseException(e);
    } finally {
        for (Closeable closeable : closeables) {
            StreamUtil.closeQuietly(closeable);
        }
        JdbcUtils.closeStatement(stmt);
    }
}
Also used : ColumnConfig(liquibase.change.ColumnConfig) SQLException(java.sql.SQLException) Closeable(java.io.Closeable) ArrayList(java.util.ArrayList) PreparedStatement(java.sql.PreparedStatement) DatabaseException(liquibase.exception.DatabaseException)

Example 5 with ColumnConfig

use of liquibase.change.ColumnConfig in project liquibase by liquibase.

the class ExecutablePreparedStatementBase method applyColumnParameter.

private void applyColumnParameter(PreparedStatement stmt, int i, ColumnConfig col) throws SQLException, DatabaseException {
    if (col.getValue() != null) {
        log.debug("value is string = " + col.getValue());
        stmt.setString(i, col.getValue());
    } else if (col.getValueBoolean() != null) {
        log.debug("value is boolean = " + col.getValueBoolean());
        stmt.setBoolean(i, col.getValueBoolean());
    } else if (col.getValueNumeric() != null) {
        log.debug("value is numeric = " + col.getValueNumeric());
        Number number = col.getValueNumeric();
        if (number instanceof ColumnConfig.ValueNumeric) {
            ColumnConfig.ValueNumeric valueNumeric = (ColumnConfig.ValueNumeric) number;
            number = valueNumeric.getDelegate();
        }
        if (number instanceof Long) {
            stmt.setLong(i, number.longValue());
        } else if (number instanceof Integer) {
            stmt.setInt(i, number.intValue());
        } else if (number instanceof Double) {
            stmt.setDouble(i, number.doubleValue());
        } else if (number instanceof Float) {
            stmt.setFloat(i, number.floatValue());
        } else if (number instanceof BigDecimal) {
            stmt.setBigDecimal(i, (BigDecimal) number);
        } else if (number instanceof BigInteger) {
            stmt.setInt(i, number.intValue());
        } else {
        // TODO: Consider throwing an exception here
        }
    } else if (col.getValueDate() != null) {
        log.debug("value is date = " + col.getValueDate());
        if (col.getValueDate() instanceof Timestamp) {
            stmt.setTimestamp(i, (Timestamp) col.getValueDate());
        } else {
            stmt.setDate(i, new java.sql.Date(col.getValueDate().getTime()));
        }
    } else if (col.getValueBlobFile() != null) {
        log.debug("value is blob = " + col.getValueBlobFile());
        try {
            LOBContent<InputStream> lob = toBinaryStream(col.getValueBlobFile());
            if (lob.length <= Integer.MAX_VALUE) {
                stmt.setBinaryStream(i, lob.content, (int) lob.length);
            } else {
                stmt.setBinaryStream(i, lob.content, lob.length);
            }
        } catch (IOException e) {
            // wrap
            throw new DatabaseException(e.getMessage(), e);
        }
    } else if (col.getValueClobFile() != null) {
        try {
            log.debug("value is clob = " + col.getValueClobFile());
            LOBContent<Reader> lob = toCharacterStream(col.getValueClobFile(), col.getEncoding());
            if (lob.length <= Integer.MAX_VALUE) {
                stmt.setCharacterStream(i, lob.content, (int) lob.length);
            } else {
                stmt.setCharacterStream(i, lob.content, lob.length);
            }
        } catch (IOException e) {
            // wrap
            throw new DatabaseException(e.getMessage(), e);
        }
    } else {
        // NULL values might intentionally be set into a change, we must also add them to the prepared statement
        log.debug("value is explicit null");
        stmt.setNull(i, java.sql.Types.NULL);
    }
}
Also used : ColumnConfig(liquibase.change.ColumnConfig) BufferedInputStream(java.io.BufferedInputStream) FileInputStream(java.io.FileInputStream) InputStream(java.io.InputStream) IOException(java.io.IOException) Timestamp(java.sql.Timestamp) BigDecimal(java.math.BigDecimal) BigInteger(java.math.BigInteger) BigInteger(java.math.BigInteger) DatabaseException(liquibase.exception.DatabaseException)

Aggregations

ColumnConfig (liquibase.change.ColumnConfig)28 Test (org.junit.Test)14 UnexpectedLiquibaseException (liquibase.exception.UnexpectedLiquibaseException)6 AddColumnConfig (liquibase.change.AddColumnConfig)5 CreateTableChange (liquibase.change.core.CreateTableChange)5 MSSQLDatabase (liquibase.database.core.MSSQLDatabase)5 SQLiteDatabase (liquibase.database.core.SQLiteDatabase)5 DatabaseException (liquibase.exception.DatabaseException)5 Sql (liquibase.sql.Sql)5 PostgresDatabase (liquibase.database.core.PostgresDatabase)4 SqlStatement (liquibase.statement.SqlStatement)4 ArrayList (java.util.ArrayList)3 ConstraintsConfig (liquibase.change.ConstraintsConfig)3 Database (liquibase.database.Database)3 DB2Database (liquibase.database.core.DB2Database)3 MySQLDatabase (liquibase.database.core.MySQLDatabase)3 UnparsedSql (liquibase.sql.UnparsedSql)3 AddUniqueConstraintStatement (liquibase.statement.core.AddUniqueConstraintStatement)3 Column (liquibase.structure.core.Column)3 IOException (java.io.IOException)2