package org.apache.blur.jdbc.parser; /** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ import java.util.ArrayList; import java.util.List; import java.util.StringTokenizer; import java.util.regex.Matcher; import java.util.regex.Pattern; public class Parser { private static final String SELECT = "select"; private static final String WHERE = "where"; private static final String FROM = "from"; private static final String SEP = new String(new char[] { 1 }); public static void main(String[] args) { // System.out.println(new // Parser().parse("select * from table where query('person.pn:(nice cool)')")); // System.out.println(new // Parser().parse("select * from table natural join table2 where person.pn = 'coandol''s' and jon='asdndandanda' And person.pf ='niorce' or nice = 'be'")); // System.out.println(new // Parser().parse("select * from table where person.pn = 'coandol''s' and jon='asdndandanda' And person.pf ='niorce' or nice = 'be'")); System.out.println(new Parser().parse("SELECT * FROM TEST_TABLE T WHERE 1 = 0")); System.out.println(new Parser().parse("select * from table t where 1 = 0")); // System.out.println(new // Parser().parse("select id,locationid,score,cf1.* from table where query('+person.pn:(nice cool) AND cool.a:nice')")); } private String where; private String tableName; private List<String> columnNames; private String tableNameAlias; public Parser parse(String query) { columnNames = getColumnNames(query); tableName = getTableName(query); tableNameAlias = getTableNameAlias(query); where = getWhere(query); return this; } private String getWhere(String query) { StringBuilder result = new StringBuilder(); StringTokenizer tokenizer = new StringTokenizer(query); while (tokenizer.hasMoreTokens()) { if (WHERE.equals(tokenizer.nextToken().toLowerCase())) { while (tokenizer.hasMoreTokens()) { String token = tokenizer.nextToken(); result.append(token).append(' '); } } } return getQuery(result.toString().trim()); } private String getQuery(String query) { Pattern p = Pattern.compile("([qQ][uU][eE][rR][yY]\\s*\\(\\s*')(.*)('\\s*\\).*)"); Matcher matcher = p.matcher(query); if (matcher.find()) { if (matcher.groupCount() != 3) {// first one is the whole string throw new RuntimeException("malformed query [" + query + "]"); } return matcher.group(2);// 2nd group is the lucene query } else { return changeQueryToLucene(query); } } private String changeQueryToLucene(String query) { query = fixAndsOrs(query); query = query.replaceAll("\\s*=\\s*", ":"); query = query.replace("''", SEP); query = query.replaceAll("'", ""); query = query.replace(SEP, "'"); return query; } private String fixAndsOrs(String query) { query = fixToUpperToken(query, "AND"); query = fixToUpperToken(query, "OR"); return query; } private String fixToUpperToken(String query, String token) { String queryUpper = query.toUpperCase(); int start = 0; int index = queryUpper.indexOf(token, start); while (index != -1) { if (!query.substring(index, index + token.length()).equals(token)) { String everythingInStringToCurrentPosition = query.substring(0, index); if (!isHitInParameter(everythingInStringToCurrentPosition)) { query = query.substring(0, index) + token + query.substring(index + token.length()); return fixToUpperToken(query, token); } } start = index + 1; index = queryUpper.indexOf(token, start); } return query; } private boolean isHitInParameter(String everythingInStringToCurrentPosition) { char[] charArray = everythingInStringToCurrentPosition.toCharArray(); int count = 0; for (int i = 0; i < charArray.length; i++) { if (charArray[i] == '\'') { count++; } } return count % 2 != 0; } private String getTableName(String query) { StringTokenizer tokenizer = new StringTokenizer(query); while (tokenizer.hasMoreTokens()) { if (FROM.equals(tokenizer.nextToken().toLowerCase())) { if (tokenizer.hasMoreTokens()) { return tokenizer.nextToken(); } } } throw new IllegalArgumentException("Table not found"); } private String getTableNameAlias(String query) { StringTokenizer tokenizer = new StringTokenizer(query); while (tokenizer.hasMoreTokens()) { if (FROM.equals(tokenizer.nextToken().toLowerCase())) { while (tokenizer.hasMoreTokens()) { tokenizer.nextToken();//table if (!tokenizer.hasMoreTokens()) { return null; } String token = tokenizer.nextToken().toLowerCase(); if (WHERE.equals(token)) { return null; } return token; } } } return null; } private List<String> getColumnNames(String query) { StringTokenizer tokenizer = new StringTokenizer(query); List<String> columnNames = new ArrayList<String>(); while (tokenizer.hasMoreTokens()) { if (SELECT.equals(tokenizer.nextToken().toLowerCase())) { while (tokenizer.hasMoreTokens()) { String token = tokenizer.nextToken().toLowerCase(); if (FROM.equals(token)) { return columnNames; } processColumnToken(columnNames, token); } } } return null; } private void processColumnToken(List<String> columnNames, String token) { StringTokenizer tokenizer = new StringTokenizer(token, ","); while (tokenizer.hasMoreTokens()) { columnNames.add(tokenizer.nextToken()); } } public String getTableName() { return trimLiteralChars(tableName); } private static String trimLiteralChars(String s) { if (s.startsWith("'") && s.endsWith("'")) { return s.substring(1, s.length() - 1); } return s; } public List<String> getColumnNames() { return removeTableAliases(columnNames); } private List<String> removeTableAliases(List<String> columnNames) { List<String> result = new ArrayList<String>(); for (String col : columnNames) { if (col.startsWith(tableNameAlias + ".")) { result.add(col.substring(tableNameAlias.length() + 1)); } else { result.add(col); } } return result; } public String getWhere() { if (where == null || where.trim().isEmpty()) { return "*"; } return where; } @Override public String toString() { return "Parser [columnNames=" + columnNames + ", tableName=" + tableName + ", where=" + where + "]"; } }