studio.raptor.sqlparser.dialect.mysql.parser.MySqlSelectParser Maven / Gradle / Ivy
/*
* Copyright 1999-2017 Alibaba Group Holding Ltd.
*
* 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.
*/
package studio.raptor.sqlparser.dialect.mysql.parser;
import java.util.List;
import studio.raptor.sqlparser.ast.SQLExpr;
import studio.raptor.sqlparser.ast.SQLSetQuantifier;
import studio.raptor.sqlparser.ast.expr.SQLIdentifierExpr;
import studio.raptor.sqlparser.ast.expr.SQLLiteralExpr;
import studio.raptor.sqlparser.ast.statement.SQLExprTableSource;
import studio.raptor.sqlparser.ast.statement.SQLSelect;
import studio.raptor.sqlparser.ast.statement.SQLSelectItem;
import studio.raptor.sqlparser.ast.statement.SQLSelectQuery;
import studio.raptor.sqlparser.ast.statement.SQLSelectQueryBlock;
import studio.raptor.sqlparser.ast.statement.SQLSubqueryTableSource;
import studio.raptor.sqlparser.ast.statement.SQLTableSource;
import studio.raptor.sqlparser.ast.statement.SQLUnionQuery;
import studio.raptor.sqlparser.ast.statement.SQLUnionQueryTableSource;
import studio.raptor.sqlparser.ast.statement.SQLUpdateSetItem;
import studio.raptor.sqlparser.dialect.mysql.ast.MySqlForceIndexHint;
import studio.raptor.sqlparser.dialect.mysql.ast.MySqlIgnoreIndexHint;
import studio.raptor.sqlparser.dialect.mysql.ast.MySqlIndexHint;
import studio.raptor.sqlparser.dialect.mysql.ast.MySqlIndexHintImpl;
import studio.raptor.sqlparser.dialect.mysql.ast.MySqlUseIndexHint;
import studio.raptor.sqlparser.dialect.mysql.ast.expr.MySqlOutFileExpr;
import studio.raptor.sqlparser.dialect.mysql.ast.statement.MySqlSelectQueryBlock;
import studio.raptor.sqlparser.dialect.mysql.ast.statement.MySqlUnionQuery;
import studio.raptor.sqlparser.dialect.mysql.ast.statement.MySqlUpdateStatement;
import studio.raptor.sqlparser.dialect.mysql.ast.statement.MySqlUpdateTableSource;
import studio.raptor.sqlparser.parser.ParserException;
import studio.raptor.sqlparser.parser.SQLExprParser;
import studio.raptor.sqlparser.parser.SQLSelectParser;
import studio.raptor.sqlparser.parser.Token;
public class MySqlSelectParser extends SQLSelectParser {
protected boolean returningFlag = false;
protected MySqlUpdateStatement updateStmt;
public MySqlSelectParser(SQLExprParser exprParser) {
super(exprParser);
}
public MySqlSelectParser(String sql) {
this(new MySqlExprParser(sql));
}
public void parseFrom(SQLSelectQueryBlock queryBlock) {
if (lexer.token() != Token.FROM) {
return;
}
lexer.nextToken();
if (lexer.token() == Token.UPDATE) { // taobao returning to urgly syntax
updateStmt = this.parseUpdateStatment();
List returnning = updateStmt.getReturning();
for (SQLSelectItem item : queryBlock.getSelectList()) {
SQLExpr itemExpr = item.getExpr();
itemExpr.setParent(updateStmt);
returnning.add(itemExpr);
}
returningFlag = true;
return;
}
queryBlock.setFrom(parseTableSource());
}
@Override
public SQLSelectQuery query() {
if (lexer.token() == (Token.LPAREN)) {
lexer.nextToken();
SQLSelectQuery select = query();
accept(Token.RPAREN);
return queryRest(select);
}
MySqlSelectQueryBlock queryBlock = new MySqlSelectQueryBlock();
if (lexer.token() == Token.SELECT) {
lexer.nextToken();
if (lexer.token() == Token.HINT) {
this.exprParser.parseHints(queryBlock.getHints());
}
if (lexer.token() == Token.COMMENT) {
lexer.nextToken();
}
if (lexer.token() == (Token.DISTINCT)) {
queryBlock.setDistionOption(SQLSetQuantifier.DISTINCT);
lexer.nextToken();
} else if (identifierEquals("DISTINCTROW")) {
queryBlock.setDistionOption(SQLSetQuantifier.DISTINCTROW);
lexer.nextToken();
} else if (lexer.token() == (Token.ALL)) {
queryBlock.setDistionOption(SQLSetQuantifier.ALL);
lexer.nextToken();
}
if (identifierEquals("HIGH_PRIORITY")) {
queryBlock.setHignPriority(true);
lexer.nextToken();
}
if (identifierEquals("STRAIGHT_JOIN")) {
queryBlock.setStraightJoin(true);
lexer.nextToken();
}
if (identifierEquals("SQL_SMALL_RESULT")) {
queryBlock.setSmallResult(true);
lexer.nextToken();
}
if (identifierEquals("SQL_BIG_RESULT")) {
queryBlock.setBigResult(true);
lexer.nextToken();
}
if (identifierEquals("SQL_BUFFER_RESULT")) {
queryBlock.setBufferResult(true);
lexer.nextToken();
}
if (identifierEquals("SQL_CACHE")) {
queryBlock.setCache(true);
lexer.nextToken();
}
if (identifierEquals("SQL_NO_CACHE")) {
queryBlock.setCache(false);
lexer.nextToken();
}
if (identifierEquals("SQL_CALC_FOUND_ROWS")) {
queryBlock.setCalcFoundRows(true);
lexer.nextToken();
}
parseSelectList(queryBlock);
parseInto(queryBlock);
}
parseFrom(queryBlock);
parseWhere(queryBlock);
parseGroupBy(queryBlock);
queryBlock.setOrderBy(this.exprParser.parseOrderBy());
if (lexer.token() == Token.LIMIT) {
queryBlock.setLimit(this.exprParser.parseLimit());
}
if (lexer.token() == Token.PROCEDURE) {
lexer.nextToken();
throw new ParserException("TODO");
}
parseInto(queryBlock);
if (lexer.token() == Token.FOR) {
lexer.nextToken();
accept(Token.UPDATE);
queryBlock.setForUpdate(true);
if (identifierEquals("NO_WAIT")) {
lexer.nextToken();
queryBlock.setNoWait(true);
} else if (identifierEquals("WAIT")) {
lexer.nextToken();
SQLExpr waitTime = this.exprParser.primary();
queryBlock.setWaitTime(waitTime);
}
}
if (lexer.token() == Token.LOCK) {
lexer.nextToken();
accept(Token.IN);
acceptIdentifier("SHARE");
acceptIdentifier("MODE");
queryBlock.setLockInShareMode(true);
}
return queryRest(queryBlock);
}
public SQLTableSource parseTableSource() {
if (lexer.token() == Token.LPAREN) {
lexer.nextToken();
SQLTableSource tableSource;
if (lexer.token() == Token.SELECT || lexer.token() == Token.WITH) {
SQLSelect select = select();
accept(Token.RPAREN);
SQLSelectQuery query = queryRest(select.getQuery());
if (query instanceof SQLUnionQuery) {
tableSource = new SQLUnionQueryTableSource((SQLUnionQuery) query);
} else {
tableSource = new SQLSubqueryTableSource(select);
}
} else if (lexer.token() == Token.LPAREN) {
tableSource = parseTableSource();
accept(Token.RPAREN);
} else {
tableSource = parseTableSource();
accept(Token.RPAREN);
}
return parseTableSourceRest(tableSource);
}
if (lexer.token() == Token.UPDATE) {
SQLTableSource tableSource = new MySqlUpdateTableSource(parseUpdateStatment());
return parseTableSourceRest(tableSource);
}
if (lexer.token() == Token.SELECT) {
throw new ParserException("TODO");
}
SQLExprTableSource tableReference = new SQLExprTableSource();
parseTableSourceQueryTableExpr(tableReference);
SQLTableSource tableSrc = parseTableSourceRest(tableReference);
if (lexer.hasComment() && lexer.isKeepComments()) {
tableSrc.addAfterComment(lexer.readAndResetComments());
}
return tableSrc;
}
protected MySqlUpdateStatement parseUpdateStatment() {
MySqlUpdateStatement update = new MySqlUpdateStatement();
lexer.nextToken();
if (identifierEquals("LOW_PRIORITY")) {
lexer.nextToken();
update.setLowPriority(true);
}
if (identifierEquals("IGNORE")) {
lexer.nextToken();
update.setIgnore(true);
}
if (identifierEquals("COMMIT_ON_SUCCESS")) {
lexer.nextToken();
update.setCommitOnSuccess(true);
}
if (identifierEquals("ROLLBACK_ON_FAIL")) {
lexer.nextToken();
update.setRollBackOnFail(true);
}
if (identifierEquals("QUEUE_ON_PK")) {
lexer.nextToken();
update.setQueryOnPk(true);
}
if (identifierEquals("TARGET_AFFECT_ROW")) {
lexer.nextToken();
SQLExpr targetAffectRow = this.exprParser.expr();
update.setTargetAffectRow(targetAffectRow);
}
SQLTableSource updateTableSource = this.exprParser.createSelectParser().parseTableSource();
update.setTableSource(updateTableSource);
accept(Token.SET);
for (; ; ) {
SQLUpdateSetItem item = this.exprParser.parseUpdateSetItem();
update.addItem(item);
if (lexer.token() != Token.COMMA) {
break;
}
lexer.nextToken();
}
if (lexer.token() == (Token.WHERE)) {
lexer.nextToken();
update.setWhere(this.exprParser.expr());
}
update.setOrderBy(this.exprParser.parseOrderBy());
update.setLimit(this.exprParser.parseLimit());
return update;
}
protected void parseInto(SQLSelectQueryBlock queryBlock) {
if (lexer.token() == (Token.INTO)) {
lexer.nextToken();
if (identifierEquals("OUTFILE")) {
lexer.nextToken();
MySqlOutFileExpr outFile = new MySqlOutFileExpr();
outFile.setFile(expr());
queryBlock.setInto(outFile);
if (identifierEquals("FIELDS") || identifierEquals("COLUMNS")) {
lexer.nextToken();
if (identifierEquals("TERMINATED")) {
lexer.nextToken();
accept(Token.BY);
}
outFile.setColumnsTerminatedBy(expr());
if (identifierEquals("OPTIONALLY")) {
lexer.nextToken();
outFile.setColumnsEnclosedOptionally(true);
}
if (identifierEquals("ENCLOSED")) {
lexer.nextToken();
accept(Token.BY);
outFile.setColumnsEnclosedBy((SQLLiteralExpr) expr());
}
if (identifierEquals("ESCAPED")) {
lexer.nextToken();
accept(Token.BY);
outFile.setColumnsEscaped((SQLLiteralExpr) expr());
}
}
if (identifierEquals("LINES")) {
lexer.nextToken();
if (identifierEquals("STARTING")) {
lexer.nextToken();
accept(Token.BY);
outFile.setLinesStartingBy((SQLLiteralExpr) expr());
} else {
identifierEquals("TERMINATED");
lexer.nextToken();
accept(Token.BY);
outFile.setLinesTerminatedBy((SQLLiteralExpr) expr());
}
}
} else {
queryBlock.setInto(this.exprParser.name());
}
}
}
protected SQLTableSource parseTableSourceRest(SQLTableSource tableSource) {
if (identifierEquals("USING")) {
return tableSource;
}
if (lexer.token() == Token.USE) {
lexer.nextToken();
MySqlUseIndexHint hint = new MySqlUseIndexHint();
parseIndexHint(hint);
tableSource.getHints().add(hint);
}
if (identifierEquals("IGNORE")) {
lexer.nextToken();
MySqlIgnoreIndexHint hint = new MySqlIgnoreIndexHint();
parseIndexHint(hint);
tableSource.getHints().add(hint);
}
if (identifierEquals("FORCE")) {
lexer.nextToken();
MySqlForceIndexHint hint = new MySqlForceIndexHint();
parseIndexHint(hint);
tableSource.getHints().add(hint);
}
if (lexer.token() == Token.PARTITION) {
lexer.nextToken();
accept(Token.LPAREN);
this.exprParser.names(((SQLExprTableSource) tableSource).getPartitions(), tableSource);
accept(Token.RPAREN);
}
return super.parseTableSourceRest(tableSource);
}
private void parseIndexHint(MySqlIndexHintImpl hint) {
if (lexer.token() == Token.INDEX) {
lexer.nextToken();
} else {
accept(Token.KEY);
}
if (lexer.token() == Token.FOR) {
lexer.nextToken();
if (lexer.token() == Token.JOIN) {
lexer.nextToken();
hint.setOption(MySqlIndexHint.Option.JOIN);
} else if (lexer.token() == Token.ORDER) {
lexer.nextToken();
accept(Token.BY);
hint.setOption(MySqlIndexHint.Option.ORDER_BY);
} else {
accept(Token.GROUP);
accept(Token.BY);
hint.setOption(MySqlIndexHint.Option.GROUP_BY);
}
}
accept(Token.LPAREN);
if (lexer.token() == Token.PRIMARY) {
lexer.nextToken();
hint.getIndexList().add(new SQLIdentifierExpr("PRIMARY"));
} else {
this.exprParser.names(hint.getIndexList());
}
accept(Token.RPAREN);
}
protected MySqlUnionQuery createSQLUnionQuery() {
return new MySqlUnionQuery();
}
public SQLUnionQuery unionRest(SQLUnionQuery union) {
if (lexer.token() == Token.LIMIT) {
MySqlUnionQuery mysqlUnionQuery = (MySqlUnionQuery) union;
mysqlUnionQuery.setLimit(this.exprParser.parseLimit());
}
return super.unionRest(union);
}
public MySqlExprParser getExprParser() {
return (MySqlExprParser) exprParser;
}
}