001 package org.codehaus.mojo.sql;
002
003 /*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements. See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership. The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License. You may obtain a copy of the License at
011 *
012 * http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied. See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022 import org.codehaus.plexus.util.StringUtils;
023
024 /**
025 * Utility class to split a long sql batch script into single SQL commands.
026 */
027 public class SqlSplitter {
028 /**
029 * Value indicating the sql has no end-delimiter like i.e. semicolon
030 */
031 public static final int NO_END = -1;
032
033 /**
034 * Check if the given sql line contains an end of command ';' Please note that we do <em>not</em> fully parse the
035 * SQL, so if we get a malformed statement, we cannot detect it.
036 *
037 * @param line
038 * to parse
039 * @param delimiter
040 * which should be used to split SQL commands
041 * @return position after the end character if the given line contains the end of a SQL script,
042 * {@value SqlSplitter#NO_END} if it doesn't contain an end char.
043 */
044 public static int containsSqlEnd(String line, String delimiter) {
045 // / * * / comments
046 boolean isComment = false;
047
048 boolean isAlphaDelimiter = StringUtils.isAlpha(delimiter);
049
050 if (line == null || line.length() == 0) {
051 return NO_END;
052 }
053
054 int pos = 0;
055
056 do {
057 if (isComment) {
058 if (line.startsWith("*/", pos)) {
059 isComment = false;
060 } else {
061 pos++;
062 continue;
063 }
064 }
065
066 if (line.startsWith("/*", pos)) {
067 isComment = true;
068 pos += 2;
069 continue;
070 }
071
072 if (line.startsWith("--", pos)) {
073 return NO_END;
074 }
075
076 if (line.startsWith("'", pos) || line.startsWith("\"", pos)) {
077 String quoteChar = "" + line.charAt(pos);
078 String quoteEscape = "\\" + quoteChar;
079 pos++;
080
081 if (line.length() <= pos) {
082 return NO_END;
083 }
084
085 do {
086 if (line.startsWith(quoteEscape, pos)) {
087 pos += 2;
088 }
089 } while (!line.startsWith(quoteChar, pos++));
090
091 continue;
092 }
093
094 if (line.startsWith(delimiter, pos)) {
095 if (isAlphaDelimiter) {
096 // check if delimiter is at start or end of line, surrounded
097 // by non-alpha character
098 if ((pos == 0 || !isAlpha(line.charAt(pos - 1)))
099 && (line.length() == pos + delimiter.length() || !isAlpha(line.charAt(pos
100 + delimiter.length())))) {
101 return pos + delimiter.length();
102 }
103 } else {
104 return pos + delimiter.length();
105 }
106 }
107
108 pos++;
109
110 } while (line.length() >= pos);
111
112 return NO_END;
113 }
114
115 /**
116 * @param c
117 * the char to check
118 * @return <code>true</code> if the given character is either a lower or an upperchase alphanumerical character
119 */
120 private static boolean isAlpha(char c) {
121 return Character.isUpperCase(c) || Character.isLowerCase(c);
122 }
123
124 }