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 }