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 /**
30 * Value indicating the sql has no end-delimiter like i.e. semicolon
31 */
32 public static final int NO_END = -1;
33
34 /**
35 * Check if the given sql line contains an end of command ';'
36 * Please note that we do <em>not</em> fully parse the SQL,
37 * so if we get a malformed statement, we cannot detect it.
38 *
39 * @param line to parse
40 * @param delimiter 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 {
46 // / * * / comments
47 boolean isComment = false;
48
49 boolean isAlphaDelimiter = StringUtils.isAlpha( delimiter );
50
51 if ( line == null || line.length() == 0 )
52 {
53 return NO_END;
54 }
55
56 int pos = 0;
57
58 do
59 {
60 if ( isComment )
61 {
62 if ( line.startsWith( "*/", pos ) )
63 {
64 isComment = false;
65 }
66 else
67 {
68 pos++;
69 continue;
70 }
71 }
72
73 if ( line.startsWith( "/*", pos ) )
74 {
75 isComment = true;
76 pos += 2;
77 continue;
78 }
79
80 if ( line.startsWith( "--", pos ) )
81 {
82 return NO_END;
83 }
84
85 if ( line.startsWith( "'", pos ) || line.startsWith( "\"", pos ) )
86 {
87 String quoteChar = "" + line.charAt( pos );
88 String quoteEscape = "\\" + quoteChar;
89 pos++;
90
91 if ( line.length() <= pos )
92 {
93 return NO_END;
94 }
95
96 do
97 {
98 if ( line.startsWith( quoteEscape, pos ) )
99 {
100 pos += 2;
101 }
102 } while ( !line.startsWith( quoteChar, pos++ ) );
103
104 continue;
105 }
106
107 if ( line.startsWith( delimiter, pos ) )
108 {
109 if ( isAlphaDelimiter )
110 {
111 // check if delimiter is at start or end of line, surrounded
112 // by non-alpha character
113 if ( ( pos == 0 || !isAlpha( line.charAt( pos - 1 ) ) )
114 && ( line.length() == pos + delimiter.length()
115 || !isAlpha( line.charAt( pos + delimiter.length() ) ) ) )
116 {
117 return pos + delimiter.length();
118 }
119 }
120 else
121 {
122 return pos + delimiter.length();
123 }
124 }
125
126 pos++;
127
128 } while ( line.length() >= pos );
129
130 return NO_END;
131 }
132
133 /**
134 * @param c the char to check
135 * @return <code>true</code> if the given character is either a lower or an upperchase alphanumerical character
136 */
137 private static boolean isAlpha( char c )
138 {
139 return Character.isUpperCase( c ) || Character.isLowerCase( c );
140 }
141
142 }