/* * 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 com.alibaba.druid.sql.dialect.mysql.parser; import com.alibaba.druid.sql.ast.SQLExpr; import com.alibaba.druid.sql.ast.SQLSetQuantifier; import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr; import com.alibaba.druid.sql.ast.expr.SQLLiteralExpr; import com.alibaba.druid.sql.ast.statement.*; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlForceIndexHint; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlIgnoreIndexHint; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlIndexHint; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlIndexHintImpl; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlUseIndexHint; import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlOutFileExpr; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock; import com.alibaba.druid.sql.ast.SQLLimit; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlUnionQuery; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlUpdateStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlUpdateTableSource; import com.alibaba.druid.sql.parser.ParserException; import com.alibaba.druid.sql.parser.SQLExprParser; import com.alibaba.druid.sql.parser.SQLSelectParser; import com.alibaba.druid.sql.parser.Token; import java.util.List; 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<SQLExpr> 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.hasComment() && lexer.isKeepComments()) { queryBlock.addBeforeComment(lexer.readAndResetComments()); } 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); parseHierachical(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; } }