package org.jbpm.persistence.scripts.util; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.apache.commons.io.FileUtils; import org.jbpm.persistence.scripts.DatabaseType; /** * Contains util methods for working with SQL script. */ public final class SQLScriptUtil { /** * Standard SQL command delimiter. */ private static final String DELIMITER_STANDARD = ";"; /** * Delimiter used in MS SQL Server database systems. */ private static final String DELIMITER_MSSQL = "GO"; /** * Extracts SQL commands from SQL script. It parses SQL script and divides it to single commands. * @param script Script from which SQL commands are extracted. * @param databaseType Database system type for which is the script written. * @return A list of SQL commands that are in specified script. * If there are no commands in the script, returns empty list. Never returns null. * @throws IOException */ public static List<String> getCommandsFromScript(final File script, final DatabaseType databaseType) throws IOException { final List<String> scriptLines = FileUtils.readLines(script); final List<String> foundCommands = new ArrayList<String>(); final StringBuilder command = new StringBuilder(); for (String line : scriptLines) { // Ignore comments. final String trimmedLine = line.trim(); if ("".equals(trimmedLine) || trimmedLine.startsWith("--") || trimmedLine.startsWith("#")) { continue; } // If the whole line is a delimiter -> add buffered command to found commands. if (trimmedLine.equals(DELIMITER_STANDARD) || ((databaseType == DatabaseType.SQLSERVER || databaseType == DatabaseType.SQLSERVER2008) && trimmedLine.equals(DELIMITER_MSSQL))) { if (!"".equals(command.toString())) { foundCommands.add(command.toString()); command.setLength(0); command.trimToSize(); } } // Split line by delimiter. if (trimmedLine.contains(DELIMITER_STANDARD)) { extractCommandsFromLine(trimmedLine, "\\" + DELIMITER_STANDARD, command, foundCommands); } else if ((databaseType == DatabaseType.SQLSERVER || databaseType == DatabaseType.SQLSERVER2008) && trimmedLine.contains(DELIMITER_MSSQL)) { extractCommandsFromLine(trimmedLine, DELIMITER_MSSQL, command, foundCommands); } else { command.append(trimmedLine).append(" "); } } // If there's still some buffered command, add it to found commands. if (!"".equals(command.toString())) { foundCommands.add(command.toString()); } return foundCommands; } /** * Extracts SQL commands from string. Divides the string (line) by specified delimiter * and adds found whole commands to extractedCommands or buffers unfinished commands. * @param line Line which is searched for SQL commands. * @param delimiter Delimiter that ends SQL command. Used for dividing specified string (line). * @param bufferedCommand Already buffered command from previous searches. * If there's some buffered command, this method appends the first * found delimited occurence to buffered command. * If there's no buffered command and the string (line) not ends * with delimiter, the last part is buffered. * @param extractedCommands Results list to which are found SQL commands added. */ private static void extractCommandsFromLine(final String line, final String delimiter, final StringBuilder bufferedCommand, final List<String> extractedCommands) { final String[] lineParts = line.split(delimiter); for (int i = 0; i < lineParts.length; i++) { // If there's some buffered command, append first found line part to it. if (i == 0) { extractedCommands.add(bufferedCommand.toString() + " " + lineParts[i]); bufferedCommand.setLength(0); bufferedCommand.trimToSize(); } else { // If the line doesn't end with delimiter, buffer the last line part. if (i == (lineParts.length - 1) && !line.endsWith(delimiter)) { bufferedCommand.append(lineParts[i]); } else { extractedCommands.add(lineParts[i]); } } } } private SQLScriptUtil() { // It makes no sense to create instances of util classes. } }