/*
* 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-13)
*/
package com.alibaba.cobar.parser.recognizer.mysql.syntax;
import static com.alibaba.cobar.parser.recognizer.mysql.MySQLToken.KW_DUAL;
import static com.alibaba.cobar.parser.recognizer.mysql.MySQLToken.KW_FROM;
import static com.alibaba.cobar.parser.recognizer.mysql.MySQLToken.KW_HAVING;
import static com.alibaba.cobar.parser.recognizer.mysql.MySQLToken.KW_IN;
import static com.alibaba.cobar.parser.recognizer.mysql.MySQLToken.KW_SELECT;
import static com.alibaba.cobar.parser.recognizer.mysql.MySQLToken.KW_UPDATE;
import static com.alibaba.cobar.parser.recognizer.mysql.MySQLToken.KW_WHERE;
import static com.alibaba.cobar.parser.recognizer.mysql.MySQLToken.PUNC_COMMA;
import java.sql.SQLSyntaxErrorException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import com.alibaba.cobar.parser.ast.expression.Expression;
import com.alibaba.cobar.parser.ast.fragment.GroupBy;
import com.alibaba.cobar.parser.ast.fragment.Limit;
import com.alibaba.cobar.parser.ast.fragment.OrderBy;
import com.alibaba.cobar.parser.ast.fragment.tableref.Dual;
import com.alibaba.cobar.parser.ast.fragment.tableref.TableReference;
import com.alibaba.cobar.parser.ast.fragment.tableref.TableReferences;
import com.alibaba.cobar.parser.ast.stmt.dml.DMLQueryStatement;
import com.alibaba.cobar.parser.ast.stmt.dml.DMLSelectStatement;
import com.alibaba.cobar.parser.ast.stmt.dml.DMLSelectUnionStatement;
import com.alibaba.cobar.parser.recognizer.mysql.MySQLToken;
import com.alibaba.cobar.parser.recognizer.mysql.lexer.MySQLLexer;
import com.alibaba.cobar.parser.util.Pair;
/**
* @author <a href="mailto:shuo.qius@alibaba-inc.com">QIU Shuo</a>
*/
public class MySQLDMLSelectParser extends MySQLDMLParser {
public MySQLDMLSelectParser(MySQLLexer lexer, MySQLExprParser exprParser) {
super(lexer, exprParser);
this.exprParser.setSelectParser(this);
}
private static enum SpecialIdentifier {
SQL_BUFFER_RESULT,
SQL_CACHE,
SQL_NO_CACHE
}
private static final Map<String, SpecialIdentifier> specialIdentifiers = new HashMap<String, SpecialIdentifier>();
static {
specialIdentifiers.put("SQL_BUFFER_RESULT", SpecialIdentifier.SQL_BUFFER_RESULT);
specialIdentifiers.put("SQL_CACHE", SpecialIdentifier.SQL_CACHE);
specialIdentifiers.put("SQL_NO_CACHE", SpecialIdentifier.SQL_NO_CACHE);
}
private DMLSelectStatement.SelectOption selectOption() throws SQLSyntaxErrorException {
for (DMLSelectStatement.SelectOption option = new DMLSelectStatement.SelectOption();; lexer.nextToken()) {
outer: switch (lexer.token()) {
case KW_ALL:
option.resultDup = DMLSelectStatement.SelectDuplicationStrategy.ALL;
break outer;
case KW_DISTINCT:
option.resultDup = DMLSelectStatement.SelectDuplicationStrategy.DISTINCT;
break outer;
case KW_DISTINCTROW:
option.resultDup = DMLSelectStatement.SelectDuplicationStrategy.DISTINCTROW;
break outer;
case KW_HIGH_PRIORITY:
option.highPriority = true;
break outer;
case KW_STRAIGHT_JOIN:
option.straightJoin = true;
break outer;
case KW_SQL_SMALL_RESULT:
option.resultSize = DMLSelectStatement.SmallOrBigResult.SQL_SMALL_RESULT;
break outer;
case KW_SQL_BIG_RESULT:
option.resultSize = DMLSelectStatement.SmallOrBigResult.SQL_BIG_RESULT;
break outer;
case KW_SQL_CALC_FOUND_ROWS:
option.sqlCalcFoundRows = true;
break outer;
case IDENTIFIER:
String optionStringUp = lexer.stringValueUppercase();
SpecialIdentifier specialId = specialIdentifiers.get(optionStringUp);
if (specialId != null) {
switch (specialId) {
case SQL_BUFFER_RESULT:
if (option.sqlBufferResult)
return option;
option.sqlBufferResult = true;
break outer;
case SQL_CACHE:
if (option.queryCache != DMLSelectStatement.QueryCacheStrategy.UNDEF)
return option;
option.queryCache = DMLSelectStatement.QueryCacheStrategy.SQL_CACHE;
break outer;
case SQL_NO_CACHE:
if (option.queryCache != DMLSelectStatement.QueryCacheStrategy.UNDEF)
return option;
option.queryCache = DMLSelectStatement.QueryCacheStrategy.SQL_NO_CACHE;
break outer;
}
}
default:
return option;
}
}
}
private List<Pair<Expression, String>> selectExprList() throws SQLSyntaxErrorException {
Expression expr = exprParser.expression();
String alias = as();
List<Pair<Expression, String>> list;
if (lexer.token() == PUNC_COMMA) {
list = new LinkedList<Pair<Expression, String>>();
list.add(new Pair<Expression, String>(expr, alias));
} else {
list = new ArrayList<Pair<Expression, String>>(1);
list.add(new Pair<Expression, String>(expr, alias));
return list;
}
for (; lexer.token() == PUNC_COMMA; list.add(new Pair<Expression, String>(expr, alias))) {
lexer.nextToken();
expr = exprParser.expression();
alias = as();
}
return list;
}
@Override
public DMLSelectStatement select() throws SQLSyntaxErrorException {
match(KW_SELECT);
DMLSelectStatement.SelectOption option = selectOption();
List<Pair<Expression, String>> exprList = selectExprList();
TableReferences tables = null;
Expression where = null;
GroupBy group = null;
Expression having = null;
OrderBy order = null;
Limit limit = null;
boolean dual = false;
if (lexer.token() == KW_FROM) {
if (lexer.nextToken() == KW_DUAL) {
lexer.nextToken();
dual = true;
List<TableReference> trs = new ArrayList<TableReference>(1);
trs.add(new Dual());
tables = new TableReferences(trs);
} else {
tables = tableRefs();
}
}
if (lexer.token() == KW_WHERE) {
lexer.nextToken();
where = exprParser.expression();
}
if (!dual) {
group = groupBy();
if (lexer.token() == KW_HAVING) {
lexer.nextToken();
having = exprParser.expression();
}
order = orderBy();
}
limit = limit();
if (!dual) {
switch (lexer.token()) {
case KW_FOR:
lexer.nextToken();
match(KW_UPDATE);
option.lockMode = DMLSelectStatement.LockMode.FOR_UPDATE;
break;
case KW_LOCK:
lexer.nextToken();
match(KW_IN);
matchIdentifier("SHARE");
matchIdentifier("MODE");
option.lockMode = DMLSelectStatement.LockMode.LOCK_IN_SHARE_MODE;
break;
}
}
return new DMLSelectStatement(option, exprList, tables, where, group, having, order, limit);
}
/**
* first token is either {@link MySQLToken#KW_SELECT} or
* {@link MySQLToken#PUNC_LEFT_PAREN} which has been scanned but not yet
* consumed
*
* @return {@link DMLSelectStatement} or {@link DMLSelectUnionStatement}
*/
public DMLQueryStatement selectUnion() throws SQLSyntaxErrorException {
DMLSelectStatement select = selectPrimary();
DMLQueryStatement query = buildUnionSelect(select);
return query;
}
}