View Javadoc

1   /**
2    * Copyright 2004-2013 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.kuali.db;
17  
18  import org.apache.commons.lang.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 that we do <em>not</em> fully parse the
31  	 * SQL, so if we get a malformed statement, we cannot detect it.
32  	 * 
33  	 * @param line
34  	 *            to parse
35  	 * @param delimiter
36  	 *            which should be used to split SQL commands
37  	 * @return position after the end character if the given line contains the end of a SQL script,
38  	 *         {@value SqlSplitter#NO_END} if it doesn't contain an end char.
39  	 */
40  	public static int containsSqlEnd(String line, String delimiter) {
41  		// / * * / comments
42  		boolean isComment = false;
43  
44  		boolean isAlphaDelimiter = StringUtils.isAlpha(delimiter);
45  
46  		if (line == null || line.length() == 0) {
47  			return NO_END;
48  		}
49  
50  		int pos = 0;
51  
52  		do {
53  			if (isComment) {
54  				if (line.startsWith("*/", pos)) {
55  					isComment = false;
56  				} else {
57  					pos++;
58  					continue;
59  				}
60  			}
61  
62  			if (line.startsWith("/*", pos)) {
63  				isComment = true;
64  				pos += 2;
65  				continue;
66  			}
67  
68  			if (line.startsWith("--", pos)) {
69  				return NO_END;
70  			}
71  
72  			if (line.startsWith("'", pos) || line.startsWith("\"", pos)) {
73  				String quoteChar = "" + line.charAt(pos);
74  				String quoteEscape = "\\" + quoteChar;
75  				pos++;
76  
77  				if (line.length() <= pos) {
78  					return NO_END;
79  				}
80  
81  				do {
82  					if (line.startsWith(quoteEscape, pos)) {
83  						pos += 2;
84  					}
85  				} while (!line.startsWith(quoteChar, pos++));
86  
87  				continue;
88  			}
89  
90  			if (line.startsWith(delimiter, pos)) {
91  				if (isAlphaDelimiter) {
92  					// check if delimiter is at start or end of line, surrounded
93  					// by non-alpha character
94  					if ((pos == 0 || !isAlpha(line.charAt(pos - 1))) && (line.length() == pos + delimiter.length() || !isAlpha(line.charAt(pos + delimiter.length())))) {
95  						return pos + delimiter.length();
96  					}
97  				} else {
98  					return pos + delimiter.length();
99  				}
100 			}
101 
102 			pos++;
103 
104 		} while (line.length() >= pos);
105 
106 		return NO_END;
107 	}
108 
109 	/**
110 	 * @param c
111 	 *            the char to check
112 	 * @return <code>true</code> if the given character is either a lower or an upperchase alphanumerical character
113 	 */
114 	private static boolean isAlpha(char c) {
115 		return Character.isUpperCase(c) || Character.isLowerCase(c);
116 	}
117 
118 }