/liquibase-core/src/main/java/liquibase/change/core/LoadDataChange.java

https://github.com/geriBatai/liquibase · Java · 250 lines · 203 code · 46 blank · 1 comment · 56 complexity · f94c68789cabc3fd92918db7e28ee212 MD5 · raw file

  1. package liquibase.change.core;
  2. import liquibase.change.*;
  3. import liquibase.database.Database;
  4. import liquibase.exception.UnexpectedLiquibaseException;
  5. import liquibase.resource.ResourceAccessor;
  6. import liquibase.statement.SqlStatement;
  7. import liquibase.statement.core.InsertStatement;
  8. import liquibase.util.StringUtils;
  9. import liquibase.util.csv.CSVReader;
  10. import java.io.IOException;
  11. import java.io.InputStream;
  12. import java.io.InputStreamReader;
  13. import java.util.ArrayList;
  14. import java.util.List;
  15. public class LoadDataChange extends AbstractChange implements ChangeWithColumns<LoadDataColumnConfig> {
  16. private String schemaName;
  17. private String tableName;
  18. private String file;
  19. private String encoding = null;
  20. private String separator = liquibase.util.csv.opencsv.CSVReader.DEFAULT_SEPARATOR + "";
  21. private String quotchar = liquibase.util.csv.opencsv.CSVReader.DEFAULT_QUOTE_CHARACTER + "";
  22. private List<LoadDataColumnConfig> columns = new ArrayList<LoadDataColumnConfig>();
  23. public LoadDataChange() {
  24. super("loadData", "Load Data", ChangeMetaData.PRIORITY_DEFAULT);
  25. }
  26. protected LoadDataChange(String changeName, String changeDescription)
  27. {
  28. super(changeName,changeDescription,ChangeMetaData.PRIORITY_DEFAULT);
  29. }
  30. public String getSchemaName() {
  31. return schemaName;
  32. }
  33. public void setSchemaName(String schemaName) {
  34. this.schemaName = StringUtils.trimToNull(schemaName);
  35. }
  36. public String getTableName() {
  37. return tableName;
  38. }
  39. public void setTableName(String tableName) {
  40. this.tableName = tableName;
  41. }
  42. public String getFile() {
  43. return file;
  44. }
  45. public void setFile(String file) {
  46. this.file = file;
  47. }
  48. public String getEncoding() {
  49. return encoding;
  50. }
  51. public void setEncoding(String encoding) {
  52. this.encoding = encoding;
  53. }
  54. public String getSeparator() {
  55. return separator;
  56. }
  57. public void setSeparator(String separator) {
  58. this.separator = separator;
  59. }
  60. public String getQuotchar() {
  61. return quotchar;
  62. }
  63. public void setQuotchar(String quotchar) {
  64. this.quotchar = quotchar;
  65. }
  66. public void addColumn(LoadDataColumnConfig column) {
  67. columns.add(column);
  68. }
  69. public List<LoadDataColumnConfig> getColumns() {
  70. return (List<LoadDataColumnConfig>) columns;
  71. }
  72. public SqlStatement[] generateStatements(Database database) {
  73. CSVReader reader = null;
  74. try {
  75. reader = getCSVReader();
  76. String[] headers = reader.readNext();
  77. if (headers == null) {
  78. throw new UnexpectedLiquibaseException("Data file "+getFile()+" was empty");
  79. }
  80. List<SqlStatement> statements = new ArrayList<SqlStatement>();
  81. String[] line = null;
  82. int lineNumber = 0;
  83. while ((line = reader.readNext()) != null) {
  84. lineNumber++;
  85. if (line.length == 0 || (line.length == 1 && StringUtils.trimToNull(line[0]) == null)) {
  86. continue; //nothing on this line
  87. }
  88. InsertStatement insertStatement = this.createStatement(getSchemaName(), getTableName());
  89. for (int i=0; i<headers.length; i++) {
  90. String columnName = null;
  91. if( i >= line.length ) {
  92. throw new UnexpectedLiquibaseException("CSV Line " + lineNumber + " has only " + (i-1) + " columns, the header has " + headers.length);
  93. }
  94. Object value = line[i];
  95. ColumnConfig columnConfig = getColumnConfig(i, headers[i]);
  96. if (columnConfig != null) {
  97. columnName = columnConfig.getName();
  98. if (value.toString().equalsIgnoreCase("NULL")) {
  99. value = "NULL";
  100. } else if (columnConfig.getType() != null) {
  101. ColumnConfig valueConfig = new ColumnConfig();
  102. if (columnConfig.getType().equalsIgnoreCase("BOOLEAN")) {
  103. valueConfig.setValueBoolean(Boolean.parseBoolean(value.toString().toLowerCase()));
  104. } else if (columnConfig.getType().equalsIgnoreCase("NUMERIC")) {
  105. valueConfig.setValueNumeric(value.toString());
  106. } else if (columnConfig.getType().toLowerCase().contains("date") ||columnConfig.getType().toLowerCase().contains("time")) {
  107. valueConfig.setValueDate(value.toString());
  108. } else if (columnConfig.getType().equalsIgnoreCase("STRING")) {
  109. valueConfig.setValue(value.toString());
  110. } else if (columnConfig.getType().equalsIgnoreCase("COMPUTED")) {
  111. valueConfig.setValue(value.toString());
  112. } else {
  113. throw new UnexpectedLiquibaseException("loadData type of "+columnConfig.getType()+" is not supported. Please use BOOLEAN, NUMERIC, DATE, STRING, or COMPUTED");
  114. }
  115. value = valueConfig.getValueObject();
  116. }
  117. }
  118. if (columnName == null) {
  119. columnName = headers[i];
  120. }
  121. insertStatement.addColumnValue(columnName, value);
  122. }
  123. statements.add(insertStatement);
  124. }
  125. return statements.toArray(new SqlStatement[statements.size()]);
  126. } catch (IOException e) {
  127. throw new RuntimeException(e);
  128. } finally {
  129. if (null != reader) {
  130. try {
  131. reader.close();
  132. } catch (IOException e) {
  133. ;
  134. }
  135. }
  136. }
  137. }
  138. protected CSVReader getCSVReader() throws IOException {
  139. ResourceAccessor opener = getResourceAccessor();
  140. if (opener == null) {
  141. throw new UnexpectedLiquibaseException("No file opener specified for "+getFile());
  142. }
  143. InputStream stream = opener.getResourceAsStream(getFile());
  144. if (stream == null) {
  145. throw new UnexpectedLiquibaseException("Data file "+getFile()+" was not found");
  146. }
  147. InputStreamReader streamReader;
  148. if (getEncoding() == null) {
  149. streamReader = new InputStreamReader(stream);
  150. } else {
  151. streamReader = new InputStreamReader(stream, getEncoding());
  152. }
  153. char quotchar;
  154. if (0 == this.quotchar.length() ) {
  155. // hope this is impossible to have a field surrounded with non ascii char 0x01
  156. quotchar = '\1';
  157. } else {
  158. quotchar = this.quotchar.charAt(0);
  159. }
  160. CSVReader reader = new CSVReader(streamReader, separator.charAt(0), quotchar );
  161. return reader;
  162. }
  163. protected InsertStatement createStatement(String schemaName, String tableName){
  164. return new InsertStatement(schemaName,tableName);
  165. }
  166. protected ColumnConfig getColumnConfig(int index, String header) {
  167. for (LoadDataColumnConfig config : columns) {
  168. if (config.getIndex() != null && config.getIndex().equals(index)) {
  169. return config;
  170. }
  171. if (config.getHeader() != null && config.getHeader().equalsIgnoreCase(header)) {
  172. return config;
  173. }
  174. if (config.getName() != null && config.getName().equalsIgnoreCase(header)) {
  175. return config;
  176. }
  177. }
  178. return null;
  179. }
  180. public String getConfirmationMessage() {
  181. return "Data loaded from "+getFile()+" into "+getTableName();
  182. }
  183. @Override
  184. public CheckSum generateCheckSum() {
  185. InputStream stream = null;
  186. try {
  187. stream = getResourceAccessor().getResourceAsStream(getFile());
  188. if (stream == null) {
  189. throw new RuntimeException(getFile() + " could not be found");
  190. }
  191. return CheckSum.compute(stream);
  192. } catch (IOException e) {
  193. throw new RuntimeException(e);
  194. } finally {
  195. if (stream != null) {
  196. try {
  197. stream.close();
  198. } catch (IOException e) {
  199. ;
  200. }
  201. }
  202. }
  203. }
  204. }