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