/*
* 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";
}
}