1 package org.codehaus.mojo.sql;
2
3 /*
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
19 * under the License.
20 */
21
22 import org.codehaus.plexus.util.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)))
99 && (line.length() == pos + delimiter.length() || !isAlpha(line.charAt(pos
100 + delimiter.length())))) {
101 return pos + delimiter.length();
102 }
103 } else {
104 return pos + delimiter.length();
105 }
106 }
107
108 pos++;
109
110 } while (line.length() >= pos);
111
112 return NO_END;
113 }
114
115 /**
116 * @param c
117 * the char to check
118 * @return <code>true</code> if the given character is either a lower or an upperchase alphanumerical character
119 */
120 private static boolean isAlpha(char c) {
121 return Character.isUpperCase(c) || Character.isLowerCase(c);
122 }
123
124 }