package liquibase.diff.output.changelog.core; import liquibase.change.Change; import liquibase.change.core.LoadDataChange; import liquibase.change.core.LoadDataColumnConfig; import liquibase.configuration.GlobalConfiguration; import liquibase.configuration.LiquibaseConfiguration; import liquibase.database.Database; import liquibase.database.jvm.JdbcConnection; import liquibase.diff.output.DiffOutputControl; import liquibase.diff.output.changelog.ChangeGeneratorChain; import liquibase.exception.UnexpectedLiquibaseException; import liquibase.servicelocator.LiquibaseService; import liquibase.structure.DatabaseObject; import liquibase.structure.core.Data; import liquibase.structure.core.Table; import liquibase.util.ISODateFormat; import liquibase.util.JdbcUtils; import liquibase.util.csv.CSVWriter; import java.io.BufferedWriter; import java.io.File; import java.io.FileOutputStream; import java.io.OutputStreamWriter; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.Date; import java.util.List; @LiquibaseService(skip = true) public class MissingDataExternalFileChangeGenerator extends MissingDataChangeGenerator { private String dataDir; public MissingDataExternalFileChangeGenerator(String dataDir) { this.dataDir = dataDir; } @Override public int getPriority(Class<? extends DatabaseObject> objectType, Database database) { if (Data.class.isAssignableFrom(objectType)) { return PRIORITY_ADDITIONAL; } return PRIORITY_NONE; } @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(100); 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)); } String fileName = table.getName().toLowerCase() + ".csv"; if (dataDir != null) { fileName = dataDir + "/" + fileName; File parentDir = new File(dataDir); if (!parentDir.exists()) { parentDir.mkdirs(); } if (!parentDir.isDirectory()) { throw new RuntimeException(parentDir + " is not a directory"); } } CSVWriter outputFile = new CSVWriter(new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName), LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getOutputEncoding()))); String[] dataTypes = new String[columnNames.size()]; String[] line = new String[columnNames.size()]; for (int i = 0; i < columnNames.size(); i++) { line[i] = columnNames.get(i); } outputFile.writeNext(line); int rowNum = 0; while (rs.next()) { line = new String[columnNames.size()]; for (int i = 0; i < columnNames.size(); i++) { Object value = JdbcUtils.getResultSetValue(rs, i + 1); if (dataTypes[i] == null && value != null) { if (value instanceof Number) { dataTypes[i] = "NUMERIC"; } else if (value instanceof Boolean) { dataTypes[i] = "BOOLEAN"; } else if (value instanceof Date) { dataTypes[i] = "DATE"; } else { dataTypes[i] = "STRING"; } } if (value == null) { line[i] = "NULL"; } else { if (value instanceof Date) { line[i] = new ISODateFormat().format(((Date) value)); } else { line[i] = value.toString(); } } } outputFile.writeNext(line); rowNum++; if (rowNum % 5000 == 0) { outputFile.flush(); } } outputFile.flush(); outputFile.close(); LoadDataChange change = new LoadDataChange(); change.setFile(fileName); change.setEncoding(LiquibaseConfiguration.getInstance().getConfiguration(GlobalConfiguration.class).getOutputEncoding()); if (outputControl.getIncludeCatalog()) { change.setCatalogName(table.getSchema().getCatalogName()); } if (outputControl.getIncludeSchema()) { change.setSchemaName(table.getSchema().getName()); } change.setTableName(table.getName()); for (int i = 0; i < columnNames.size(); i++) { String colName = columnNames.get(i); LoadDataColumnConfig columnConfig = new LoadDataColumnConfig(); columnConfig.setHeader(colName); columnConfig.setName(colName); columnConfig.setType(dataTypes[i]); change.addColumn(columnConfig); } return new Change[]{ change }; } 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) { } } } } }