All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.unitils.dbmaintainer.script.impl.SQLScriptParser Maven / Gradle / Ivy

Go to download

Unitils provides utilities to further simplify unit-testing with JUnit, DBUnit, EasyMock Hibernate and Spring. The goal is to make unit-testing easy and maintainable by offering utilities such as automatic DB-schema maintainance and equality assertion through reflection.

There is a newer version: 3.4.6
Show newest version
/*
 * Copyright 2006-2007,  Unitils.org
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.unitils.dbmaintainer.script.impl;

import java.util.ArrayList;
import java.util.List;

/**
 * A class for parsing statements out of sql scripts.
 * 

* All statements should be separated with a semicolon (;). The last statement will be * added even if it does not end with a semicolon. The semicolons will not be included in the returned statements. *

* All comments in-line (--comment) and block (/ * comment * /) are removed from the statements. * This parser also takes quotedOrEmpty literals and double quotedOrEmpty text into account when parsing the statements and treating * the comments. *

* New line charactars within quotes and double quotes will be inclded in the statements, other new lines will * be replaced by a single space. * * @author Tim Ducheyne * @author Filip Neven */ public class SQLScriptParser { /** * The normal, not in quotes, not in comment state. */ protected static final int NORMAL = 0; /** * The in an in-line comment (-- comment) state. */ protected static final int IN_LINE_COMMENT = 1; /** * The in a block comment (/ * comment * /) state. */ protected static final int IN_BLOCK_COMMENT = 2; /** * The in single quotes ('text') state. */ protected static final int IN_SINGLE_QUOTES = 3; /** * The in double quotes ("text") state. */ protected static final int IN_DOUBLE_QUOTES = 4; /** * The current state */ protected int state = NORMAL; /** * Parses all statements out of the given script as described in the class javadoc. * * @param script the script, not null * @return the statements, not null */ public List parseStatements(String script) { List statements = new ArrayList(); StringBuffer statement = new StringBuffer(); // loop over all chars and pass current and next char to handle methods (use 0 for next of last char) char[] chars = script.toCharArray(); int length = chars.length; for (int i = 0; i < length; i++) { boolean skipNext = handleChar(chars[i], (i + 1 < length) ? chars[i + 1] : 0, statement, statements); if (skipNext) { i++; } } // Check whether last statement was not ended with a ; if (statement.length() > 0) { String trimmedStatement = statement.toString().trim(); if (trimmedStatement.length() > 0) { statements.add(trimmedStatement); } } return statements; } /** * Handles a char by delegating it to the method corresponding to the current state. * * @param current the current char * @param next the next char, 0 if there is no next char * @param statement the current statement buffer, not null * @param statements the statement list, not null * @return true if the next char should be skipped */ protected boolean handleChar(char current, char next, StringBuffer statement, List statements) { switch (state) { case IN_LINE_COMMENT: return handleCharInLineComment(current, next, statement, statements); case IN_BLOCK_COMMENT: return handleCharInBlockComment(current, next, statement, statements); case IN_SINGLE_QUOTES: return handleCharInSingleQuotes(current, next, statement, statements); case IN_DOUBLE_QUOTES: return handleCharInDoubleQuotes(current, next, statement, statements); default: return handleCharNormal(current, next, statement, statements); } } /** * Handles a char in the normal (not quotedOrEmpty, not commented) state. Checks for the beginning of a * line comment (-- comment), block comment (/ * comment * /), quotedOrEmpty text ('text') and double * quotedOrEmpty text ("text) and changes the state correspondingly. It also checks for the ending of * statements by a ;. If a statement is ended the it is trimmed and added to the statement list ( ; not included). * New line chars (\n and \r) will be replaced by a single space. * * @param current the current char * @param next the next char, 0 if there is no next char * @param statement the current statement buffer, not null * @param statements the statement list, not null * @return true if the next char should be skipped */ public boolean handleCharNormal(char current, char next, StringBuffer statement, List statements) { // check line comment if (current == '-' && next == '-') { state = IN_LINE_COMMENT; return true; } // check block comment if (current == '/' && next == '*') { state = IN_BLOCK_COMMENT; return true; } // check new line: replace by space if previous char or next char is not a space if (current == '\n' || current == '\r') { if (next != ' ' && (statement.length() == 0 || statement.charAt(statement.length() - 1) != ' ')) { statement.append(' '); } return false; } // check escaped characters (do not interpreted next char) if (current == '\\') { statement.append(current); statement.append(next); return true; } // check ending of statement if (current == ';') { statements.add(statement.toString().trim()); statement.setLength(0); return false; } // check single and double quotes if (current == '\'') { state = IN_SINGLE_QUOTES; } else if (current == '"') { state = IN_DOUBLE_QUOTES; } // append all chars statement.append(current); return false; } /** * Handles a char in a line comment (-- comment). Looks for an end of line to end the comment. Skips all other chars. * * @param current the current char * @param next the next char, 0 if there is no next char * @param statement the current statement buffer, not null * @param statements the statement list, not null * @return true if the next char should be skipped */ protected boolean handleCharInLineComment(char current, char next, StringBuffer statement, List statements) { // check for ending chars if (current == '\n' || current == '\r') { if (next != ' ' && (statement.length() == 0 || statement.charAt(statement.length() - 1) != ' ')) { statement.append(' '); } state = NORMAL; } // skip all chars return false; } /** * Handles char in a block comment. Checks for the ending of the comment * followed by /. Skips all other chars. * * @param current the current char * @param next the next char, 0 if there is no next char * @param statement the current statement buffer, not null * @param statements the statement list, not null * @return true if the next char should be skipped */ protected boolean handleCharInBlockComment(char current, char next, StringBuffer statement, List statements) { // check for ending chars if (current == '*' && next == '/') { statement.append(' '); state = NORMAL; return true; } // skip all chars return false; } /** * Handles a char in a quotedOrEmpty literal ('text'). Checks for the ending quote, but ignores escaped quotes. All * chars, including newlines (\n \r), are appended to the statement. * * @param current the current char * @param next the next char, 0 if there is no next char * @param statement the current statement buffer, not null * @param statements the statement list, not null * @return true if the next char should be skipped */ public boolean handleCharInSingleQuotes(char current, char next, StringBuffer statement, List statements) { // check for escaped quotes if (current == '\\' || (current == '\'' && next == '\'')) { statement.append(current); statement.append(next); return true; } // check for ending quote if (current == '\'') { state = NORMAL; } // append all chars statement.append(current); return false; } /** * Handles a char in a double quotedOrEmpty string ("text"). Checks for the ending double quote, but ignores escaped * double quotes. All chars, including newlines (\n \r), are appended to the statement. * * @param current the current char * @param next the next char, 0 if there is no next char * @param statement the current statement buffer, not null * @param statements the statement list, not null * @return true if the next char should be skipped */ public boolean handleCharInDoubleQuotes(char current, char next, StringBuffer statement, List statements) { // check for escaped double quotes if (current == '\\' || (current == '"' && next == '"')) { statement.append(current); statement.append(next); return true; } // check for ending quote if (current == '"') { state = NORMAL; } // append all chars statement.append(current); return false; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy