/* * Copyright 1999-2012 Alibaba Group. * * 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. */ /** * (created at 2011-5-9) */ package com.alibaba.cobar.parser.recognizer.mysql.syntax; import static com.alibaba.cobar.parser.recognizer.mysql.MySQLToken.KW_AS; import static com.alibaba.cobar.parser.recognizer.mysql.MySQLToken.KW_JOIN; import static com.alibaba.cobar.parser.recognizer.mysql.MySQLToken.KW_SELECT; import static com.alibaba.cobar.parser.recognizer.mysql.MySQLToken.KW_UNION; import static com.alibaba.cobar.parser.recognizer.mysql.MySQLToken.PUNC_COMMA; import static com.alibaba.cobar.parser.recognizer.mysql.MySQLToken.PUNC_LEFT_PAREN; import static com.alibaba.cobar.parser.recognizer.mysql.MySQLToken.PUNC_RIGHT_PAREN; import java.sql.SQLSyntaxErrorException; import java.util.ArrayList; import java.util.List; import com.alibaba.cobar.parser.recognizer.mysql.lexer.MySQLLexer; /** * @author <a href="mailto:shuo.qius@alibaba-inc.com">QIU Shuo</a> */ public class SoloParser extends MySQLParser { public SoloParser(MySQLLexer lexer) { super(lexer); } public Refs refs() throws SQLSyntaxErrorException { Refs refs = new Refs(); for (;;) { Ref ref = ref(); refs.addRef(ref); if (lexer.token() == PUNC_COMMA) { lexer.nextToken(); } else { return refs; } } } public Ref buildRef(Ref first) throws SQLSyntaxErrorException { for (; lexer.token() == KW_JOIN;) { lexer.nextToken(); Ref temp = factor(); first = new Join(first, temp); } return first; } public Ref ref() throws SQLSyntaxErrorException { return buildRef(factor()); } public Ref factor() throws SQLSyntaxErrorException { String alias; if (lexer.token() == PUNC_LEFT_PAREN) { lexer.nextToken(); Ref queryRefs = refsOrQuery(); match(PUNC_RIGHT_PAREN); if (queryRefs instanceof Query) { match(KW_AS); alias = lexer.stringValue(); lexer.nextToken(); return new SubQuery((Query) queryRefs, alias); } return queryRefs; } String tableName = lexer.stringValue(); lexer.nextToken(); if (lexer.token() == KW_AS) { lexer.nextToken(); alias = lexer.stringValue(); lexer.nextToken(); return new Factor(tableName, alias); } return new Factor(tableName, null); } /** * first <code>(</code> has been consumed */ public Ref refsOrQuery() throws SQLSyntaxErrorException { Ref temp; Refs rst; Union u; switch (lexer.token()) { case KW_SELECT: u = new Union(); for (;;) { Select s = selectPrimary(); u.addSelect(s); if (lexer.token() == KW_UNION) { lexer.nextToken(); } else { break; } } if (u.selects.size() == 1) { return u.selects.get(0); } return u; case PUNC_LEFT_PAREN: lexer.nextToken(); temp = refsOrQuery(); match(PUNC_RIGHT_PAREN); if (temp instanceof Query) { if (temp instanceof Select) { if (lexer.token() == KW_UNION) { u = new Union(); u.addSelect((Select) temp); while (lexer.token() == KW_UNION) { lexer.nextToken(); temp = selectPrimary(); u.addSelect((Select) temp); } return u; } } if (lexer.token() == KW_AS) { lexer.nextToken(); String alias = lexer.stringValue(); temp = new SubQuery((Query) temp, alias); lexer.nextToken(); } else { return temp; } } // ---- build factor complete--------------- temp = buildRef(temp); // ---- build ref complete--------------- break; default: temp = ref(); } if (lexer.token() == PUNC_COMMA) { rst = new Refs(); rst.addRef(temp); for (; lexer.token() == PUNC_COMMA;) { lexer.nextToken(); temp = ref(); rst.addRef(temp); } return rst; } return temp; } /** * first <code>SELECT</code> or <code>(</code> has not been consumed */ private Select selectPrimary() throws SQLSyntaxErrorException { Select s = null; if (lexer.token() == PUNC_LEFT_PAREN) { lexer.nextToken(); s = selectPrimary(); match(PUNC_RIGHT_PAREN); return s; } match(KW_SELECT); return new Select(); } public static void main(String[] args) throws SQLSyntaxErrorException { String sql = " ( ( select union select union select) as j join (((select union (select)) as t ) join t2 ) ,(select)as d), t3)"; // String sql = // "((select) as s1, (((( select union select ) as t2)) join (((t2),t4 as t))) ), t1 aS T1"; // String sql = // " (( select union select union select) as j ,(select)as d), t3"; System.out.println(sql); MySQLLexer lexer = new MySQLLexer(sql); lexer.nextToken(); SoloParser p = new SoloParser(lexer); Refs refs = p.refs(); System.out.println(refs); } } interface Ref { } class Factor implements Ref { String tableName; String alias; public Factor(String tableName, String alias) { super(); this.tableName = tableName; this.alias = alias; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append(tableName); sb.append(" AS "); sb.append(alias); return sb.toString(); } } class SubQuery implements Ref { Query u; String alias; public SubQuery(Query u, String alias) { super(); this.u = u; this.alias = alias; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("("); sb.append(u); sb.append(") AS "); sb.append(alias); return sb.toString(); } } class Join implements Ref { Ref left; Ref right; public Join(Ref left, Ref right) { super(); this.left = left; this.right = right; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("<"); sb.append(left.toString()); sb.append(" JOIN "); sb.append(right.toString()); sb.append(">"); return sb.toString(); } } class Refs implements Ref { List<Ref> refs = new ArrayList<Ref>(); public void addRef(Ref ref) { refs.add(ref); } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("["); for (int i = 0; i < refs.size(); ++i) { if (i > 0) { sb.append(", "); } sb.append(refs.get(i).toString()); } sb.append("]"); return sb.toString(); } } interface Query { } class Union implements Query, Ref { List<Select> selects = new ArrayList<Select>(); public void addSelect(Select select) { selects.add(select); } @SuppressWarnings("unused") @Override public String toString() { StringBuilder sb = new StringBuilder(); for (Select s : selects) { sb.append(" UNION SELECT"); } String rst = sb.toString(); int i = rst.indexOf("UNION"); if (i >= 0) { rst = rst.substring(i + "UNION".length()); } return rst; } } class Select implements Query, Ref { @Override public String toString() { return "SELECT"; } }