![JAR search and dependency download from the Maven repository](/logo.png)
org.codehaus.mojo.sql.SqlSplitter Maven / Gradle / Ivy
The newest version!
package org.codehaus.mojo.sql;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
import org.codehaus.plexus.util.StringUtils;
/**
* Utility class to split a long sql batch script into single SQL commands.
*/
public final class SqlSplitter
{
private SqlSplitter()
{
// hide utility class constructor
}
/**
* Value indicating the sql has no end-delimiter like i.e. the semicolon.
*/
public static final int NO_END = -1;
/**
* parsed sql started a single quote static text which continues on the next line (did not end)
*/
public static final int OVERFLOW_SINGLE_QUOTE = -2;
/**
* parsed sql started a double quote static text which continues on the next line (did not end)
*/
public static final int OVERFLOW_DOUBLE_QUOTE = -4;
/**
* parsed sql started a comment with /_* which continues on the next line (did not end)
*/
public static final int OVERFLOW_COMMENT = -8;
/**
* Check if the given sql line contains a delimiter representing the end of the command. Please note that we do
* not fully parse the SQL, so if we get a malformed statement, we cannot detect it.
*
* @param line to parse
* @param delimiter which should be used to split SQL commands
* @param overflowValue 0=none, {@link SqlSplitter#OVERFLOW_COMMENT}, {@link SqlSplitter#OVERFLOW_SINGLE_QUOTE} or
* {@link SqlSplitter#OVERFLOW_DOUBLE_QUOTE}
* @return position after the end character if the given line contains the end of a SQL script,
* {@link SqlSplitter#NO_END} if it doesn't contain an end char. {@link SqlSplitter#OVERFLOW_SINGLE_QUOTE}
* will be returned if a single quote didn't get closed, {@link SqlSplitter#OVERFLOW_DOUBLE_QUOTE} likewise
* for not closed double quotes.
*/
public static int containsSqlEnd( String line, String delimiter, final int overflowValue )
{
int ret = overflowValue >= 0 ? NO_END : overflowValue;
// / * * / comments
boolean isComment = ( overflowValue == OVERFLOW_COMMENT );
String quoteChar = null;
if ( overflowValue == OVERFLOW_SINGLE_QUOTE )
{
quoteChar = "'";
}
else if ( overflowValue == OVERFLOW_DOUBLE_QUOTE )
{
quoteChar = "\"";
}
boolean isAlphaDelimiter = StringUtils.isAlpha( delimiter );
if ( line == null || line.length() == 0 )
{
return ret;
}
int pos = 0;
int maxpos = line.length() - 1;
char c1;
char c2 = line.charAt( 0 );
statement: do
{
if ( isComment )
{
do
{
// keep c2 in line
if ( pos < maxpos )
{
c2 = line.charAt( pos + 1 );
}
if ( startsWith( line, '*', pos ) && startsWith( line, '/', pos + 1 ) )
{
ret = NO_END;
isComment = false;
continue statement;
}
}
while ( pos++ < maxpos );
// reached EOL
break statement;
}
// if in quote-mode, search for end quote, respecting escaped characters
if ( quoteChar != null )
{
String doubleQuote = quoteChar + quoteChar;
do
{
// keep c2 in line
if ( pos < maxpos )
{
c2 = line.charAt( pos + 1 );
}
if ( startsWith( line, "\\", pos ) || startsWith( line, doubleQuote, pos ) )
{
// skip next character, but stay in quote-mode
pos++;
}
else if ( startsWith( line, quoteChar, pos ) )
{
ret = NO_END;
quoteChar = null;
continue statement;
}
}
while ( pos++ < maxpos );
// reach EOL
break statement;
}
// use the nextchar from the previous iteration
c1 = c2;
if ( pos < maxpos )
{
// and set the following char
c2 = line.charAt( pos + 1 );
}
else
{
// or reset to blank if the line has ended
c2 = ' ';
}
// verify if current char indicates start of new quoted block
if ( c1 == '\'' || c1 == '"' )
{
quoteChar = String.valueOf( c1 );
ret = quoteChar.equals( "'" ) ? OVERFLOW_SINGLE_QUOTE : OVERFLOW_DOUBLE_QUOTE;
continue statement;
}
// parse for a / * start of comment
if ( c1 == '/' && c2 == '*' )
{
isComment = true;
pos++;
ret = OVERFLOW_COMMENT;
continue statement;
}
if ( c1 == '-' && c2 == '-' )
{
return ret;
}
if ( startsWith( line, delimiter, pos ) )
{
if ( isAlphaDelimiter )
{
// check if delimiter is at start or end of line, surrounded
// by non-alpha character
if ( ( pos == 0 || !isAlpha( line.charAt( pos - 1 ) ) )
&& ( line.length() == pos + delimiter.length()
|| !isAlpha( line.charAt( pos + delimiter.length() ) ) ) )
{
return pos + delimiter.length();
}
}
else
{
return pos + delimiter.length();
}
}
}
while ( maxpos > pos++ );
return ret;
}
/**
* Small performance optimized replacement for {@link String#startsWith(String, int)}.
*
* @param toParse the String to parse
* @param delimiter the delimiter to look for
* @param position the initial position to start the scan with
*/
private static boolean startsWith( String toParse, String delimiter, int position )
{
if ( delimiter.length() == 1 )
{
return toParse.length() > position && toParse.charAt( position ) == delimiter.charAt( 0 );
}
else
{
return toParse.startsWith( delimiter, position );
}
}
/**
* @param toParse the String to parse
* @param delimiter the delimiter to look for
* @param position the initial position to start the scan with
* @return
*/
private static boolean startsWith( String toParse, char delimiter, int position )
{
return toParse.length() > position && toParse.charAt( position ) == delimiter;
}
/**
* @param c the char to check
* @return true
if the given character is either a lower or an upperchase alphanumerical character
*/
private static boolean isAlpha( char c )
{
return Character.isUpperCase( c ) || Character.isLowerCase( c );
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy