/* * Copyright 2014 TWO SIGMA OPEN SOURCE, LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.twosigma.beaker.sql; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class QueryParser { private static final List<ParsingState> PARSING_STATES = Arrays.asList( new ParsingState("'", "'", false), // string literal new ParsingState("/*", "*/", true), new LineCommentParsingState("--"), new LineCommentParsingState("%%") ); public static List<String> split(String script) { StringBuilder sb = new StringBuilder(script); ParsingState currentState = null; int stateStart = -1; for(int i = 0; i < sb.length();) { if (currentState != null) { if (currentState.isEnd(sb, i)) { if (currentState.mustBeDeleted()) { int stateEnd = currentState.skipEnd(i); sb = new StringBuilder().append(sb.substring(0, stateStart)).append(sb.substring(stateEnd)); i = stateStart; } else { i = currentState.skipEnd(i); } currentState = null; } else { i++; } } else { ParsingState state = getSuitableState(sb, i); if (state != null) { currentState = state; stateStart = i; i = state.skipStart(i); } else { i++; } } } //ToDo replace to custom splitter - need for ignore 'xx;yy' etc. String[] splittedQueries = sb.toString().split(";"); List<String> listOfQueries = new ArrayList<>(); for (int i = 0; i < splittedQueries.length; i++) { if (!splittedQueries[i].trim().equals("") && !splittedQueries[i].trim().equals("\t")) { listOfQueries.add(splittedQueries[i].trim()); } } return listOfQueries; } private static ParsingState getSuitableState(StringBuilder line, int index) { for (ParsingState eachState : PARSING_STATES) { if (eachState.isStart(line, index)) { return eachState; } } return null; } private static class LineCommentParsingState extends ParsingState { public LineCommentParsingState(String start) { super(start, "\n", true); } } private static class ParsingState { private String start; private String end; private boolean mustBeDeleted; public ParsingState(String start, String end, boolean mustBeDeleted) { this.start = start; this.end = end; this.mustBeDeleted = mustBeDeleted; } public boolean isStart(StringBuilder line, int index) { return isAtPosition(line, index, start); } public int skipStart(int index) { return index + start.length(); } public boolean isEnd(StringBuilder line, int index) { return isAtPosition(line, index, end); } public int skipEnd(int index) { return index + end.length(); } private boolean isAtPosition(StringBuilder line, int index, String element) { int endIndex = index + element.length(); return line.length() >= endIndex && line.substring(index, endIndex).equals(element); } public boolean mustBeDeleted() { return mustBeDeleted; } } }