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