View Javadoc

1   /**
2    * Copyright 2006-2012 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.codehaus.mojo.sql;
17  
18  import org.codehaus.plexus.util.StringUtils;
19  
20  /**
21   * Utility class to split a long sql batch script into single SQL commands.
22   */
23  public class SqlSplitter {
24  	/**
25  	 * Value indicating the sql has no end-delimiter like i.e. semicolon
26  	 */
27  	public static final int NO_END = -1;
28  
29  	/**
30  	 * Check if the given sql line contains an end of command ';' Please note
31  	 * that we do <em>not</em> fully parse the SQL, so if we get a malformed
32  	 * statement, we cannot detect it.
33  	 * 
34  	 * @param line
35  	 *            to parse
36  	 * @param delimiter
37  	 *            which should be used to split SQL commands
38  	 * @return position after the end character if the given line contains the
39  	 *         end of a SQL script, {@value SqlSplitter#NO_END} if it doesn't
40  	 *         contain an end char.
41  	 */
42  	public static int containsSqlEnd(String line, String delimiter) {
43  		// / * * / comments
44  		boolean isComment = false;
45  
46  		boolean isAlphaDelimiter = StringUtils.isAlpha(delimiter);
47  
48  		if (line == null || line.length() == 0) {
49  			return NO_END;
50  		}
51  
52  		int pos = 0;
53  
54  		do {
55  			if (isComment) {
56  				if (line.startsWith("*/", pos)) {
57  					isComment = false;
58  				} else {
59  					pos++;
60  					continue;
61  				}
62  			}
63  
64  			if (line.startsWith("/*", pos)) {
65  				isComment = true;
66  				pos += 2;
67  				continue;
68  			}
69  
70  			if (line.startsWith("--", pos)) {
71  				return NO_END;
72  			}
73  
74  			if (line.startsWith("'", pos) || line.startsWith("\"", pos)) {
75  				String quoteChar = "" + line.charAt(pos);
76  				String quoteEscape = "\\" + quoteChar;
77  				pos++;
78  
79  				if (line.length() <= pos) {
80  					return NO_END;
81  				}
82  
83  				do {
84  					if (line.startsWith(quoteEscape, pos)) {
85  						pos += 2;
86  					}
87  				} while (!line.startsWith(quoteChar, pos++));
88  
89  				continue;
90  			}
91  
92  			if (line.startsWith(delimiter, pos)) {
93  				if (isAlphaDelimiter) {
94  					// check if delimiter is at start or end of line, surrounded
95  					// by non-alpha character
96  					if ((pos == 0 || !isAlpha(line.charAt(pos - 1)))
97  							&& (line.length() == pos + delimiter.length() || !isAlpha(line
98  									.charAt(pos + delimiter.length())))) {
99  						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 }