View Javadoc

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