001 /** 002 * Copyright 2006-2011 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 package org.codehaus.mojo.sql; 017 018 import org.codehaus.plexus.util.StringUtils; 019 020 /** 021 * Utility class to split a long sql batch script into single SQL commands. 022 */ 023 public class SqlSplitter { 024 /** 025 * Value indicating the sql has no end-delimiter like i.e. semicolon 026 */ 027 public static final int NO_END = -1; 028 029 /** 030 * Check if the given sql line contains an end of command ';' Please note 031 * that we do <em>not</em> fully parse the SQL, so if we get a malformed 032 * statement, we cannot detect it. 033 * 034 * @param line 035 * to parse 036 * @param delimiter 037 * which should be used to split SQL commands 038 * @return position after the end character if the given line contains the 039 * end of a SQL script, {@value SqlSplitter#NO_END} if it doesn't 040 * contain an end char. 041 */ 042 public static int containsSqlEnd(String line, String delimiter) { 043 // / * * / comments 044 boolean isComment = false; 045 046 boolean isAlphaDelimiter = StringUtils.isAlpha(delimiter); 047 048 if (line == null || line.length() == 0) { 049 return NO_END; 050 } 051 052 int pos = 0; 053 054 do { 055 if (isComment) { 056 if (line.startsWith("*/", pos)) { 057 isComment = false; 058 } else { 059 pos++; 060 continue; 061 } 062 } 063 064 if (line.startsWith("/*", pos)) { 065 isComment = true; 066 pos += 2; 067 continue; 068 } 069 070 if (line.startsWith("--", pos)) { 071 return NO_END; 072 } 073 074 if (line.startsWith("'", pos) || line.startsWith("\"", pos)) { 075 String quoteChar = "" + line.charAt(pos); 076 String quoteEscape = "\\" + quoteChar; 077 pos++; 078 079 if (line.length() <= pos) { 080 return NO_END; 081 } 082 083 do { 084 if (line.startsWith(quoteEscape, pos)) { 085 pos += 2; 086 } 087 } while (!line.startsWith(quoteChar, pos++)); 088 089 continue; 090 } 091 092 if (line.startsWith(delimiter, pos)) { 093 if (isAlphaDelimiter) { 094 // check if delimiter is at start or end of line, surrounded 095 // by non-alpha character 096 if ((pos == 0 || !isAlpha(line.charAt(pos - 1))) 097 && (line.length() == pos + delimiter.length() || !isAlpha(line 098 .charAt(pos + delimiter.length())))) { 099 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 117 * upperchase alphanumerical character 118 */ 119 private static boolean isAlpha(char c) { 120 return Character.isUpperCase(c) || Character.isLowerCase(c); 121 } 122 123 }