All Downloads are FREE. Search and download functionalities are using the official Maven repository.

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




© 2015 - 2024 Weber Informatics LLC | Privacy Policy