Coverage Report - liquibase.parser.core.formattedsql.FormattedSqlChangeLogParser
 
Classes in this File Line Coverage Branch Coverage Complexity
FormattedSqlChangeLogParser
84%
100/119
82%
28/34
6.333
 
 1  
 package liquibase.parser.core.formattedsql;
 2  
 
 3  
 import java.io.BufferedReader;
 4  
 import java.io.IOException;
 5  
 import java.io.InputStream;
 6  
 import java.io.InputStreamReader;
 7  
 import java.util.regex.Matcher;
 8  
 import java.util.regex.Pattern;
 9  
 
 10  
 import liquibase.change.core.EmptyChange;
 11  
 import liquibase.change.core.RawSQLChange;
 12  
 import liquibase.changelog.ChangeLogParameters;
 13  
 import liquibase.changelog.ChangeSet;
 14  
 import liquibase.changelog.DatabaseChangeLog;
 15  
 import liquibase.exception.ChangeLogParseException;
 16  
 import liquibase.exception.UnsupportedChangeException;
 17  
 import liquibase.logging.LogFactory;
 18  
 import liquibase.parser.ChangeLogParser;
 19  
 import liquibase.resource.ResourceAccessor;
 20  
 import liquibase.util.StringUtils;
 21  
 
 22  21
 public class FormattedSqlChangeLogParser implements ChangeLogParser {
 23  
 
 24  
     @Override
 25  
     public boolean supports(String changeLogFile, ResourceAccessor resourceAccessor) {
 26  10
         BufferedReader reader = null;
 27  
         try {
 28  10
             if (changeLogFile.endsWith(".sql")) {
 29  2
                 reader = new BufferedReader(new InputStreamReader(openChangeLogFile(changeLogFile, resourceAccessor)));
 30  
 
 31  2
                 return reader.readLine().startsWith("--liquibase formatted");
 32  
             } else {
 33  8
                 return false;
 34  
             }
 35  0
         } catch (IOException e) {
 36  0
             LogFactory.getLogger().debug("Exception reading " + changeLogFile, e);
 37  0
             return false;
 38  
         } finally {
 39  10
             if (reader != null) {
 40  
                 try {
 41  2
                     reader.close();
 42  0
                 } catch (IOException e) {
 43  0
                     LogFactory.getLogger().debug("Exception closing " + changeLogFile, e);
 44  12
                 }
 45  
             }
 46  
         }
 47  
     }
 48  
 
 49  
     @Override
 50  
     public int getPriority() {
 51  38
         return PRIORITY_DEFAULT + 5;
 52  
     }
 53  
 
 54  
     @Override
 55  
     public DatabaseChangeLog parse(String physicalChangeLogLocation, ChangeLogParameters changeLogParameters,
 56  
             ResourceAccessor resourceAccessor) throws ChangeLogParseException {
 57  
 
 58  1
         DatabaseChangeLog changeLog = new DatabaseChangeLog();
 59  1
         changeLog.setPhysicalFilePath(physicalChangeLogLocation);
 60  
 
 61  1
         BufferedReader reader = null;
 62  
 
 63  
         try {
 64  1
             reader = new BufferedReader(new InputStreamReader(openChangeLogFile(physicalChangeLogLocation,
 65  
                     resourceAccessor)));
 66  1
             StringBuffer currentSql = new StringBuffer();
 67  1
             StringBuffer currentRollbackSql = new StringBuffer();
 68  
 
 69  1
             ChangeSet changeSet = null;
 70  1
             RawSQLChange change = null;
 71  1
             Pattern changeSetPattern = Pattern.compile("\\-\\-changeset (\\w+):(\\w+).*", Pattern.CASE_INSENSITIVE);
 72  1
             Pattern rollbackPattern = Pattern.compile("\\s*\\-\\-rollback (.*)", Pattern.CASE_INSENSITIVE);
 73  1
             Pattern stripCommentsPattern = Pattern.compile(".*stripComments:(\\w+).*", Pattern.CASE_INSENSITIVE);
 74  1
             Pattern splitStatementsPattern = Pattern.compile(".*splitStatements:(\\w+).*", Pattern.CASE_INSENSITIVE);
 75  1
             Pattern endDelimiterPattern = Pattern.compile(".*endDelimiter:(\\w+).*", Pattern.CASE_INSENSITIVE);
 76  
 
 77  1
             Pattern runOnChangePattern = Pattern.compile(".*runOnChange:(\\w+).*", Pattern.CASE_INSENSITIVE);
 78  1
             Pattern runAlwaysPattern = Pattern.compile(".*runAlways:(\\w+).*", Pattern.CASE_INSENSITIVE);
 79  1
             Pattern contextPattern = Pattern.compile(".*context:(\\w+).*", Pattern.CASE_INSENSITIVE);
 80  1
             Pattern runInTransactionPattern = Pattern.compile(".*runInTransaction:(\\w+).*", Pattern.CASE_INSENSITIVE);
 81  1
             Pattern dbmsPattern = Pattern.compile(".*dbms:(\\w+).*", Pattern.CASE_INSENSITIVE);
 82  1
             Pattern failOnErrorPattern = Pattern.compile(".*failOnError:(\\w+).*", Pattern.CASE_INSENSITIVE);
 83  
 
 84  
             String line;
 85  28
             while ((line = reader.readLine()) != null) {
 86  27
                 Matcher changeSetPatternMatcher = changeSetPattern.matcher(line);
 87  27
                 if (changeSetPatternMatcher.matches()) {
 88  5
                     String finalCurrentSql = StringUtils.trimToNull(currentSql.toString());
 89  5
                     if (changeSet != null) {
 90  
 
 91  4
                         if (finalCurrentSql == null) {
 92  0
                             throw new ChangeLogParseException("No SQL for changeset " + changeSet.toString(false));
 93  
                         }
 94  
 
 95  4
                         change.setSql(finalCurrentSql);
 96  
 
 97  4
                         if (StringUtils.trimToNull(currentRollbackSql.toString()) != null) {
 98  
                             try {
 99  3
                                 if (currentRollbackSql.toString().trim().toLowerCase().matches("^not required.*")) {
 100  1
                                     changeSet.addRollbackChange(new EmptyChange());
 101  
                                 } else {
 102  2
                                     RawSQLChange rollbackChange = new RawSQLChange();
 103  2
                                     rollbackChange.setSql(currentRollbackSql.toString());
 104  2
                                     changeSet.addRollbackChange(rollbackChange);
 105  
                                 }
 106  0
                             } catch (UnsupportedChangeException e) {
 107  0
                                 throw new RuntimeException(e);
 108  3
                             }
 109  
                         }
 110  
                     }
 111  
 
 112  5
                     Matcher stripCommentsPatternMatcher = stripCommentsPattern.matcher(line);
 113  5
                     Matcher splitStatementsPatternMatcher = splitStatementsPattern.matcher(line);
 114  5
                     Matcher endDelimiterPatternMatcher = endDelimiterPattern.matcher(line);
 115  
 
 116  5
                     Matcher runOnChangePatternMatcher = runOnChangePattern.matcher(line);
 117  5
                     Matcher runAlwaysPatternMatcher = runAlwaysPattern.matcher(line);
 118  5
                     Matcher contextPatternMatcher = contextPattern.matcher(line);
 119  5
                     Matcher runInTransactionPatternMatcher = runInTransactionPattern.matcher(line);
 120  5
                     Matcher dbmsPatternMatcher = dbmsPattern.matcher(line);
 121  5
                     Matcher failOnErrorPatternMatcher = failOnErrorPattern.matcher(line);
 122  
 
 123  5
                     boolean stripComments = parseBoolean(stripCommentsPatternMatcher, changeSet, true);
 124  5
                     boolean splitStatements = parseBoolean(splitStatementsPatternMatcher, changeSet, true);
 125  5
                     boolean runOnChange = parseBoolean(runOnChangePatternMatcher, changeSet, false);
 126  5
                     boolean runAlways = parseBoolean(runAlwaysPatternMatcher, changeSet, false);
 127  5
                     boolean runInTransaction = parseBoolean(runInTransactionPatternMatcher, changeSet, true);
 128  5
                     boolean failOnError = parseBoolean(failOnErrorPatternMatcher, changeSet, true);
 129  
 
 130  5
                     String endDelimiter = parseString(endDelimiterPatternMatcher);
 131  5
                     String context = parseString(contextPatternMatcher);
 132  5
                     String dbms = parseString(dbmsPatternMatcher);
 133  
 
 134  5
                     changeSet = new ChangeSet(changeSetPatternMatcher.group(2), changeSetPatternMatcher.group(1),
 135  
                             runAlways, runOnChange, physicalChangeLogLocation, context, dbms, runInTransaction);
 136  5
                     changeSet.setFailOnError(failOnError);
 137  5
                     changeLog.addChangeSet(changeSet);
 138  
 
 139  5
                     change = new RawSQLChange();
 140  5
                     change.setSql(finalCurrentSql);
 141  5
                     change.setResourceAccessor(resourceAccessor);
 142  5
                     change.setSplitStatements(splitStatements);
 143  5
                     change.setStripComments(stripComments);
 144  5
                     change.setEndDelimiter(endDelimiter);
 145  5
                     changeSet.addChange(change);
 146  
 
 147  5
                     currentSql = new StringBuffer();
 148  5
                     currentRollbackSql = new StringBuffer();
 149  5
                 } else {
 150  22
                     if (changeSet != null) {
 151  20
                         Matcher rollbackMatcher = rollbackPattern.matcher(line);
 152  20
                         if (rollbackMatcher.matches()) {
 153  5
                             if (rollbackMatcher.groupCount() == 1) {
 154  5
                                 currentRollbackSql.append(rollbackMatcher.group(1)).append("\n");
 155  
                             }
 156  
                         } else {
 157  15
                             currentSql.append(line).append("\n");
 158  
                         }
 159  
                     }
 160  
                 }
 161  27
             }
 162  
 
 163  1
             if (changeSet != null) {
 164  1
                 change.setSql(StringUtils.trimToNull(currentSql.toString()));
 165  
 
 166  1
                 if (StringUtils.trimToNull(currentRollbackSql.toString()) != null) {
 167  
                     try {
 168  1
                         if (currentRollbackSql.toString().trim().toLowerCase().matches("^not required.*")) {
 169  1
                             changeSet.addRollbackChange(new EmptyChange());
 170  
                         } else {
 171  0
                             RawSQLChange rollbackChange = new RawSQLChange();
 172  0
                             rollbackChange.setSql(currentRollbackSql.toString());
 173  0
                             changeSet.addRollbackChange(rollbackChange);
 174  
                         }
 175  0
                     } catch (UnsupportedChangeException e) {
 176  0
                         throw new RuntimeException(e);
 177  1
                     }
 178  
                 }
 179  
             }
 180  
 
 181  0
         } catch (IOException e) {
 182  0
             throw new ChangeLogParseException(e);
 183  
         } finally {
 184  1
             if (reader != null) {
 185  
                 try {
 186  1
                     reader.close();
 187  0
                 } catch (IOException ignore) {
 188  1
                 }
 189  
             }
 190  
         }
 191  
 
 192  1
         return changeLog;
 193  
     }
 194  
 
 195  
     private String parseString(Matcher matcher) {
 196  15
         String endDelimiter = null;
 197  15
         if (matcher.matches()) {
 198  3
             endDelimiter = matcher.group(1);
 199  
         }
 200  15
         return endDelimiter;
 201  
     }
 202  
 
 203  
     private boolean parseBoolean(Matcher matcher, ChangeSet changeSet, boolean defaultValue)
 204  
             throws ChangeLogParseException {
 205  30
         boolean stripComments = defaultValue;
 206  30
         if (matcher.matches()) {
 207  
             try {
 208  6
                 stripComments = Boolean.parseBoolean(matcher.group(1));
 209  0
             } catch (Exception e) {
 210  0
                 throw new ChangeLogParseException("Cannot parse " + changeSet + " "
 211  
                         + matcher.toString().replaceAll("\\.*", "") + " as a boolean");
 212  6
             }
 213  
         }
 214  30
         return stripComments;
 215  
     }
 216  
 
 217  
     protected InputStream openChangeLogFile(String physicalChangeLogLocation, ResourceAccessor resourceAccessor)
 218  
             throws IOException {
 219  0
         return resourceAccessor.getResourceAsStream(physicalChangeLogLocation);
 220  
     }
 221  
 }