From d57060d7823721780e79e9c1c046a5cd8c7e5f8c Mon Sep 17 00:00:00 2001 From: wenshao Date: Tue, 30 Jul 2013 16:41:08 +0800 Subject: [PATCH] bug fixed for wall provider --- doc/license.txt | 2 +- .../mysql/parser/MySqlSelectParser.java | 689 +-- .../mysql/parser/MySqlStatementParser.java | 5173 ++++++++--------- .../com/alibaba/druid/wall/WallProvider.java | 1420 ++--- .../bvt/filter/wall/MySqlWallTest93.java | 2 +- .../bvt/filter/wall/MySqlWallTest94.java | 43 + 6 files changed, 3688 insertions(+), 3641 deletions(-) create mode 100644 src/test/java/com/alibaba/druid/bvt/filter/wall/MySqlWallTest94.java diff --git a/doc/license.txt b/doc/license.txt index 696c2a748c..dbadc0ac15 100644 --- a/doc/license.txt +++ b/doc/license.txt @@ -1,4 +1,4 @@ -Copyright 1999-2013 Alibaba Group Holding Ltd. +Copyright 1999-2011 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. diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlSelectParser.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlSelectParser.java index 10d1f4c99e..4547f4326e 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlSelectParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlSelectParser.java @@ -1,342 +1,347 @@ -/* - * Copyright 1999-2011 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.SQLSelectGroupByClause; -import com.alibaba.druid.sql.ast.statement.SQLSelectQuery; -import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock; -import com.alibaba.druid.sql.ast.statement.SQLTableSource; -import com.alibaba.druid.sql.ast.statement.SQLUnionQuery; -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.MySqlSelectGroupBy; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock.Limit; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlUnionQuery; -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; - -public class MySqlSelectParser extends SQLSelectParser { - - public MySqlSelectParser(SQLExprParser exprParser){ - super(exprParser); - } - - public MySqlSelectParser(String sql){ - this(new MySqlExprParser(sql)); - } - - @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); - - 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((SQLLiteralExpr) 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()); - } - } - } - - parseFrom(queryBlock); - - parseWhere(queryBlock); - - parseGroupBy(queryBlock); - - queryBlock.setOrderBy(this.exprParser.parseOrderBy()); - - if (lexer.token() == Token.LIMIT) { - queryBlock.setLimit(parseLimit()); - } - - if (identifierEquals("PROCEDURE")) { - lexer.nextToken(); - throw new ParserException("TODO"); - } - - if (lexer.token() == Token.INTO) { - lexer.nextToken(); - SQLExpr expr = this.exprParser.name(); - queryBlock.setInto(expr); - } - - if (lexer.token() == Token.FOR) { - lexer.nextToken(); - accept(Token.UPDATE); - - queryBlock.setForUpdate(true); - } - - if (lexer.token() == Token.LOCK) { - lexer.nextToken(); - accept(Token.IN); - acceptIdentifier("SHARE"); - acceptIdentifier("MODE"); - queryBlock.setLockInShareMode(true); - } - - return queryRest(queryBlock); - } - - protected void parseGroupBy(SQLSelectQueryBlock queryBlock) { - if (lexer.token() == (Token.GROUP)) { - lexer.nextToken(); - accept(Token.BY); - - SQLSelectGroupByClause groupBy = new SQLSelectGroupByClause(); - while (true) { - groupBy.getItems().add(this.exprParser.expr()); - if (!(lexer.token() == (Token.COMMA))) { - break; - } - lexer.nextToken(); - } - - if (identifierEquals("WITH")) { - lexer.nextToken(); - acceptIdentifier("ROLLUP"); - - MySqlSelectGroupBy mySqlGroupBy = new MySqlSelectGroupBy(); - mySqlGroupBy.getItems().addAll(groupBy.getItems()); - mySqlGroupBy.setRollUp(true); - - groupBy = mySqlGroupBy; - } - - if (lexer.token() == Token.HAVING) { - lexer.nextToken(); - - groupBy.setHaving(this.exprParser.expr()); - } - - queryBlock.setGroupBy(groupBy); - } - } - - 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); - } - - 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(parseLimit()); - } - return super.unionRest(union); - } - - public Limit parseLimit() { - return ((MySqlExprParser) this.exprParser).parseLimit(); - } -} +/* + * Copyright 1999-2011 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.SQLSelectGroupByClause; +import com.alibaba.druid.sql.ast.statement.SQLSelectQuery; +import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock; +import com.alibaba.druid.sql.ast.statement.SQLTableSource; +import com.alibaba.druid.sql.ast.statement.SQLUnionQuery; +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.MySqlSelectGroupBy; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock.Limit; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlUnionQuery; +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; + +public class MySqlSelectParser extends SQLSelectParser { + + public MySqlSelectParser(SQLExprParser exprParser){ + super(exprParser); + } + + public MySqlSelectParser(String sql){ + this(new MySqlExprParser(sql)); + } + + @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); + + 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((SQLLiteralExpr) 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()); + } + } + } + + parseFrom(queryBlock); + + parseWhere(queryBlock); + + parseGroupBy(queryBlock); + + queryBlock.setOrderBy(this.exprParser.parseOrderBy()); + + if (lexer.token() == Token.LIMIT) { + queryBlock.setLimit(parseLimit()); + } + + if (identifierEquals("PROCEDURE")) { + lexer.nextToken(); + throw new ParserException("TODO"); + } + + if (lexer.token() == Token.INTO) { + lexer.nextToken(); + SQLExpr expr = this.exprParser.name(); + queryBlock.setInto(expr); + } + + if (lexer.token() == Token.FOR) { + lexer.nextToken(); + accept(Token.UPDATE); + + queryBlock.setForUpdate(true); + } + + if (lexer.token() == Token.LOCK) { + lexer.nextToken(); + accept(Token.IN); + acceptIdentifier("SHARE"); + acceptIdentifier("MODE"); + queryBlock.setLockInShareMode(true); + } + + return queryRest(queryBlock); + } + + protected void parseGroupBy(SQLSelectQueryBlock queryBlock) { + SQLSelectGroupByClause groupBy = null; + + if (lexer.token() == Token.GROUP) { + groupBy = new SQLSelectGroupByClause(); + + lexer.nextToken(); + accept(Token.BY); + + while (true) { + groupBy.getItems().add(this.exprParser.expr()); + if (!(lexer.token() == (Token.COMMA))) { + break; + } + lexer.nextToken(); + } + + if (identifierEquals("WITH")) { + lexer.nextToken(); + acceptIdentifier("ROLLUP"); + + MySqlSelectGroupBy mySqlGroupBy = new MySqlSelectGroupBy(); + mySqlGroupBy.getItems().addAll(groupBy.getItems()); + mySqlGroupBy.setRollUp(true); + + groupBy = mySqlGroupBy; + } + } + + if (lexer.token() == Token.HAVING) { + lexer.nextToken(); + + if (groupBy == null) { + groupBy = new SQLSelectGroupByClause(); + } + groupBy.setHaving(this.exprParser.expr()); + } + + queryBlock.setGroupBy(groupBy); + } + + 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); + } + + 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(parseLimit()); + } + return super.unionRest(union); + } + + public Limit parseLimit() { + return ((MySqlExprParser) this.exprParser).parseLimit(); + } +} diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlStatementParser.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlStatementParser.java index cdc7763d1b..44c08698f6 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlStatementParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlStatementParser.java @@ -1,2587 +1,2586 @@ -/* - * Copyright 1999-2011 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 java.util.ArrayList; -import java.util.List; - -import com.alibaba.druid.sql.ast.SQLCommentHint; -import com.alibaba.druid.sql.ast.SQLExpr; -import com.alibaba.druid.sql.ast.SQLName; -import com.alibaba.druid.sql.ast.SQLOrderBy; -import com.alibaba.druid.sql.ast.SQLStatement; -import com.alibaba.druid.sql.ast.expr.SQLCharExpr; -import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr; -import com.alibaba.druid.sql.ast.expr.SQLListExpr; -import com.alibaba.druid.sql.ast.expr.SQLLiteralExpr; -import com.alibaba.druid.sql.ast.expr.SQLQueryExpr; -import com.alibaba.druid.sql.ast.expr.SQLVariantRefExpr; -import com.alibaba.druid.sql.ast.statement.SQLAlterTableAddForeignKey; -import com.alibaba.druid.sql.ast.statement.SQLAlterTableAddPrimaryKey; -import com.alibaba.druid.sql.ast.statement.SQLAlterTableAlterColumn; -import com.alibaba.druid.sql.ast.statement.SQLAlterTableDisableConstraint; -import com.alibaba.druid.sql.ast.statement.SQLAlterTableDisableKeys; -import com.alibaba.druid.sql.ast.statement.SQLAlterTableDropColumnItem; -import com.alibaba.druid.sql.ast.statement.SQLAlterTableDropConstraint; -import com.alibaba.druid.sql.ast.statement.SQLAlterTableDropForeinKey; -import com.alibaba.druid.sql.ast.statement.SQLAlterTableDropIndex; -import com.alibaba.druid.sql.ast.statement.SQLAlterTableDropPrimaryKey; -import com.alibaba.druid.sql.ast.statement.SQLAlterTableEnableConstraint; -import com.alibaba.druid.sql.ast.statement.SQLAlterTableEnableKeys; -import com.alibaba.druid.sql.ast.statement.SQLAlterTableStatement; -import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition; -import com.alibaba.druid.sql.ast.statement.SQLCreateDatabaseStatement; -import com.alibaba.druid.sql.ast.statement.SQLCreateTableStatement; -import com.alibaba.druid.sql.ast.statement.SQLDropTableStatement; -import com.alibaba.druid.sql.ast.statement.SQLDropViewStatement; -import com.alibaba.druid.sql.ast.statement.SQLInsertStatement; -import com.alibaba.druid.sql.ast.statement.SQLInsertStatement.ValuesClause; -import com.alibaba.druid.sql.ast.statement.SQLPrimaryKey; -import com.alibaba.druid.sql.ast.statement.SQLSelect; -import com.alibaba.druid.sql.ast.statement.SQLSelectOrderByItem; -import com.alibaba.druid.sql.ast.statement.SQLSelectStatement; -import com.alibaba.druid.sql.ast.statement.SQLSetStatement; -import com.alibaba.druid.sql.ast.statement.SQLTableSource; -import com.alibaba.druid.sql.ast.statement.SQLUpdateSetItem; -import com.alibaba.druid.sql.ast.statement.SQLUpdateStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.MySqlForeignKey; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.CobarShowStatus; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableAddColumn; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableAddIndex; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableAddUnique; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableChangeColumn; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableCharacter; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableDiscardTablespace; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableImportTablespace; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableModifyColumn; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableOption; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlBinlogStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCommitStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateIndexStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateTableStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateUserStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlDeleteStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlDescribeStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlDropTableStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlDropUser; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlDropViewStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlExecuteStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlHelpStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlInsertStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlKillStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlLoadDataInFileStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlLoadXmlStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlLockTableStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlLockTableStatement.LockType; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlPrepareStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlRenameTableStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlReplaceStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlResetStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlRollbackStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock.Limit; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSetCharSetStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSetNamesStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSetTransactionIsolationLevelStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowAuthorsStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowBinLogEventsStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowBinaryLogsStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowCharacterSetStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowCollationStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowColumnsStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowContributorsStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowCreateDatabaseStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowCreateEventStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowCreateFunctionStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowCreateProcedureStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowCreateTableStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowCreateTriggerStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowCreateViewStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowDatabasesStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowEngineStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowEnginesStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowErrorsStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowEventsStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowFunctionCodeStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowFunctionStatusStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowGrantsStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowIndexesStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowKeysStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowMasterLogsStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowMasterStatusStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowOpenTablesStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowPluginsStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowPrivilegesStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowProcedureCodeStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowProcedureStatusStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowProcessListStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowProfileStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowProfilesStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowRelayLogEventsStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowSlaveHostsStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowSlaveStatusStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowStatusStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowTableStatusStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowTablesStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowTriggersStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowVariantsStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowWarningsStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlStartTransactionStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlUnlockTablesStatement; -import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlUpdateStatement; -import com.alibaba.druid.sql.parser.Lexer; -import com.alibaba.druid.sql.parser.ParserException; -import com.alibaba.druid.sql.parser.SQLSelectParser; -import com.alibaba.druid.sql.parser.SQLStatementParser; -import com.alibaba.druid.sql.parser.Token; - -public class MySqlStatementParser extends SQLStatementParser { - - private static final String AUTO_INCREMENT = "AUTO_INCREMENT"; - private static final String COLLATE2 = "COLLATE"; - private static final String CASCADE = "CASCADE"; - private static final String RESTRICT = "RESTRICT"; - private static final String CHAIN = "CHAIN"; - private static final String ENGINES = "ENGINES"; - private static final String ENGINE = "ENGINE"; - private static final String BINLOG = "BINLOG"; - private static final String EVENTS = "EVENTS"; - private static final String CHARACTER = "CHARACTER"; - private static final String SESSION = "SESSION"; - private static final String GLOBAL = "GLOBAL"; - private static final String VARIABLES = "VARIABLES"; - private static final String ERRORS = "ERRORS"; - private static final String STATUS = "STATUS"; - private static final String IGNORE = "IGNORE"; - private static final String RESET = "RESET"; - private static final String DESCRIBE = "DESCRIBE"; - private static final String DESC = "DESC"; - private static final String WRITE = "WRITE"; - private static final String READ = "READ"; - private static final String LOCAL = "LOCAL"; - private static final String TABLES = "TABLES"; - private static final String TEMPORARY = "TEMPORARY"; - private static final String USER = "USER"; - private static final String SPATIAL = "SPATIAL"; - private static final String FULLTEXT = "FULLTEXT"; - private static final String DELAYED = "DELAYED"; - private static final String LOW_PRIORITY = "LOW_PRIORITY"; - - public MySqlStatementParser(String sql){ - super(new MySqlExprParser(sql)); - } - - public MySqlStatementParser(Lexer lexer){ - super(new MySqlExprParser(lexer)); - } - - public SQLCreateTableStatement parseCreateTable() { - MySqlCreateTableParser parser = new MySqlCreateTableParser(this.exprParser); - return parser.parseCrateTable(); - } - - public SQLSelectStatement parseSelect() { - MySqlSelectParser selectParser = new MySqlSelectParser(this.exprParser); - return new SQLSelectStatement(selectParser.select()); - } - - public SQLUpdateStatement parseUpdateStatement() { - MySqlUpdateStatement stmt = createUpdateStatement(); - - if (lexer.token() == Token.UPDATE) { - lexer.nextToken(); - - if (identifierEquals(LOW_PRIORITY)) { - lexer.nextToken(); - stmt.setLowPriority(true); - } - - if (identifierEquals(IGNORE)) { - lexer.nextToken(); - stmt.setIgnore(true); - } - - SQLTableSource tableSource = this.exprParser.createSelectParser().parseTableSource(); - stmt.setTableSource(tableSource); - } - - parseUpdateSet(stmt); - - if (lexer.token() == (Token.WHERE)) { - lexer.nextToken(); - stmt.setWhere(this.exprParser.expr()); - } - - stmt.setOrderBy(this.exprParser.parseOrderBy()); - - stmt.setLimit(parseLimit()); - - return stmt; - } - - protected MySqlUpdateStatement createUpdateStatement() { - return new MySqlUpdateStatement(); - } - - public MySqlDeleteStatement parseDeleteStatement() { - MySqlDeleteStatement deleteStatement = new MySqlDeleteStatement(); - - if (lexer.token() == Token.DELETE) { - lexer.nextToken(); - - if (lexer.token() == Token.COMMENT) { - lexer.nextToken(); - } - - if (identifierEquals(LOW_PRIORITY)) { - deleteStatement.setLowPriority(true); - lexer.nextToken(); - } - - if (identifierEquals("QUICK")) { - deleteStatement.setQuick(true); - lexer.nextToken(); - } - - if (identifierEquals(IGNORE)) { - deleteStatement.setIgnore(true); - lexer.nextToken(); - } - - if (lexer.token() == Token.IDENTIFIER) { - deleteStatement.setTableSource(createSQLSelectParser().parseTableSource()); - - if (lexer.token() == Token.FROM) { - lexer.nextToken(); - SQLTableSource tableSource = createSQLSelectParser().parseTableSource(); - deleteStatement.setFrom(tableSource); - } - } else { - if (lexer.token() == Token.FROM) { - lexer.nextToken(); - deleteStatement.setTableSource(createSQLSelectParser().parseTableSource()); - } - } - - if (identifierEquals("USING")) { - lexer.nextToken(); - - SQLTableSource tableSource = createSQLSelectParser().parseTableSource(); - deleteStatement.setUsing(tableSource); - } - } - - if (lexer.token() == (Token.WHERE)) { - lexer.nextToken(); - SQLExpr where = this.exprParser.expr(); - deleteStatement.setWhere(where); - } - - if (lexer.token() == (Token.ORDER)) { - SQLOrderBy orderBy = exprParser.parseOrderBy(); - deleteStatement.setOrderBy(orderBy); - } - - deleteStatement.setLimit(parseLimit()); - - return deleteStatement; - } - - public SQLStatement parseCreate() { - char markChar = lexer.current(); - int markBp = lexer.bp(); - - accept(Token.CREATE); - - boolean replace = false; - if (lexer.token() == Token.OR) { - lexer.nextToken(); - accept(Token.REPLACE); - replace = true; - } - - List hints = this.exprParser.parseHints(); - - if (lexer.token() == Token.TABLE || identifierEquals(TEMPORARY)) { - if (replace) { - lexer.reset(markBp, markChar, Token.CREATE); - } - MySqlCreateTableParser parser = new MySqlCreateTableParser(this.exprParser); - MySqlCreateTableStatement stmt = parser.parseCrateTable(false); - stmt.setHints(hints); - return stmt; - } - - if (lexer.token() == Token.DATABASE) { - if (replace) { - lexer.reset(markBp, markChar, Token.CREATE); - } - return parseCreateDatabase(); - } - - if (lexer.token() == Token.UNIQUE || lexer.token() == Token.INDEX || identifierEquals(FULLTEXT) - || identifierEquals(SPATIAL)) { - if (replace) { - lexer.reset(markBp, markChar, Token.CREATE); - } - return parseCreateIndex(); - } - - if (identifierEquals(USER)) { - if (replace) { - lexer.reset(markBp, markChar, Token.CREATE); - } - return parseCreateUser(); - } - - if (lexer.token() == Token.VIEW) { - if (replace) { - lexer.reset(markBp, markChar, Token.CREATE); - } - - return parseCreateView(); - } - - throw new ParserException("TODO " + lexer.token()); - } - - public SQLStatement parseCreateIndex() { - MySqlCreateIndexStatement stmt = new MySqlCreateIndexStatement(); - - if (lexer.token() == Token.UNIQUE) { - stmt.setType("UNIQUE"); - lexer.nextToken(); - } else if (identifierEquals(FULLTEXT)) { - stmt.setType(FULLTEXT); - lexer.nextToken(); - } else if (identifierEquals(SPATIAL)) { - stmt.setType(SPATIAL); - lexer.nextToken(); - } - - accept(Token.INDEX); - - stmt.setName(this.exprParser.name()); - - parseCreateIndexUsing(stmt); - - accept(Token.ON); - - stmt.setTable(this.exprParser.name()); - - accept(Token.LPAREN); - - for (;;) { - SQLSelectOrderByItem item = this.exprParser.parseSelectOrderByItem(); - stmt.getItems().add(item); - if (lexer.token() == Token.COMMA) { - lexer.nextToken(); - continue; - } - break; - } - accept(Token.RPAREN); - - parseCreateIndexUsing(stmt); - - return stmt; - } - - private void parseCreateIndexUsing(MySqlCreateIndexStatement stmt) { - if (identifierEquals("USING")) { - lexer.nextToken(); - - if (identifierEquals("BTREE")) { - stmt.setUsing("BTREE"); - lexer.nextToken(); - } else if (identifierEquals("HASH")) { - stmt.setUsing("HASH"); - lexer.nextToken(); - } else { - throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); - } - } - } - - public SQLStatement parseCreateUser() { - if (lexer.token() == Token.CREATE) { - lexer.nextToken(); - } - - acceptIdentifier(USER); - - MySqlCreateUserStatement stmt = new MySqlCreateUserStatement(); - - for (;;) { - MySqlCreateUserStatement.UserSpecification userSpec = new MySqlCreateUserStatement.UserSpecification(); - - SQLExpr expr = exprParser.primary(); - userSpec.setUser(expr); - - if (lexer.token() == Token.IDENTIFIED) { - lexer.nextToken(); - if (lexer.token() == Token.BY) { - lexer.nextToken(); - - if (identifierEquals("PASSWORD")) { - lexer.nextToken(); - } - - SQLCharExpr password = (SQLCharExpr) this.exprParser.expr(); - userSpec.setPassword(password); - } else if (lexer.token() == Token.WITH) { - lexer.nextToken(); - - SQLCharExpr text = (SQLCharExpr) this.exprParser.expr(); - userSpec.setAuthPlugin(text); - } - } - - stmt.getUsers().add(userSpec); - - if (lexer.token() == Token.COMMA) { - lexer.nextToken(); - continue; - } - - break; - } - - return stmt; - } - - public SQLStatement parseKill() { - accept(Token.KILL); - - MySqlKillStatement stmt = new MySqlKillStatement(); - - if (identifierEquals("CONNECTION")) { - stmt.setType(MySqlKillStatement.Type.CONNECTION); - lexer.nextToken(); - } else if (identifierEquals("QUERY")) { - stmt.setType(MySqlKillStatement.Type.QUERY); - lexer.nextToken(); - } else { - throw new ParserException("not support kill type " + lexer.token()); - } - - SQLExpr threadId = this.exprParser.expr(); - stmt.setThreadId(threadId); - - return stmt; - } - - public SQLStatement parseBinlog() { - acceptIdentifier("binlog"); - - MySqlBinlogStatement stmt = new MySqlBinlogStatement(); - - SQLExpr expr = this.exprParser.expr(); - stmt.setExpr(expr); - - return stmt; - } - - public SQLStatement parseReset() { - acceptIdentifier(RESET); - - MySqlResetStatement stmt = new MySqlResetStatement(); - - for (;;) { - if (lexer.token() == Token.IDENTIFIER) { - if (identifierEquals("QUERY")) { - lexer.nextToken(); - acceptIdentifier("CACHE"); - stmt.getOptions().add("QUERY CACHE"); - } else { - stmt.getOptions().add(lexer.stringVal()); - lexer.nextToken(); - } - - if (lexer.token() == Token.COMMA) { - lexer.nextToken(); - continue; - } - } - break; - } - - return stmt; - } - - public boolean parseStatementListDialect(List statementList) { - if (lexer.token() == Token.KILL) { - SQLStatement stmt = parseKill(); - statementList.add(stmt); - return true; - } - - if (identifierEquals("PREPARE")) { - MySqlPrepareStatement stmt = parsePrepare(); - statementList.add(stmt); - return true; - } - - if (identifierEquals("EXECUTE")) { - MySqlExecuteStatement stmt = parseExecute(); - statementList.add(stmt); - return true; - } - - if (identifierEquals("LOAD")) { - SQLStatement stmt = parseLoad(); - statementList.add(stmt); - return true; - } - - if (lexer.token() == Token.REPLACE) { - MySqlReplaceStatement stmt = parseReplicate(); - statementList.add(stmt); - return true; - } - - if (identifierEquals("START")) { - MySqlStartTransactionStatement stmt = parseStart(); - statementList.add(stmt); - return true; - } - - if (lexer.token() == Token.SHOW) { - SQLStatement stmt = parseShow(); - statementList.add(stmt); - return true; - } - - if (identifierEquals(BINLOG)) { - SQLStatement stmt = parseBinlog(); - statementList.add(stmt); - return true; - } - - if (identifierEquals(RESET)) { - SQLStatement stmt = parseReset(); - statementList.add(stmt); - return true; - } - - if (identifierEquals("HELP")) { - lexer.nextToken(); - MySqlHelpStatement stmt = new MySqlHelpStatement(); - stmt.setContent(this.exprParser.primary()); - statementList.add(stmt); - return true; - } - - if (identifierEquals(DESC) || identifierEquals(DESCRIBE)) { - SQLStatement stmt = parseDescribe(); - statementList.add(stmt); - return true; - } - - if (lexer.token() == Token.LOCK) { - lexer.nextToken(); - acceptIdentifier(TABLES); - - MySqlLockTableStatement stmt = new MySqlLockTableStatement(); - stmt.setTableSource(this.exprParser.name()); - - if (identifierEquals(READ)) { - lexer.nextToken(); - if (identifierEquals(LOCAL)) { - lexer.nextToken(); - stmt.setLockType(LockType.READ_LOCAL); - } else { - stmt.setLockType(LockType.READ); - } - } else if (identifierEquals(WRITE)) { - stmt.setLockType(LockType.WRITE); - } else if (identifierEquals(LOW_PRIORITY)) { - lexer.nextToken(); - acceptIdentifier(WRITE); - stmt.setLockType(LockType.LOW_PRIORITY_WRITE); - } - - statementList.add(stmt); - return true; - } - - if (identifierEquals("UNLOCK")) { - lexer.nextToken(); - acceptIdentifier(TABLES); - statementList.add(new MySqlUnlockTablesStatement()); - return true; - } - - return false; - } - - public MySqlDescribeStatement parseDescribe() { - if (lexer.token() == Token.DESC || identifierEquals(DESCRIBE)) { - lexer.nextToken(); - } else { - throw new ParserException("expect DESC, actual " + lexer.token()); - } - - MySqlDescribeStatement stmt = new MySqlDescribeStatement(); - stmt.setObject(this.exprParser.name()); - - return stmt; - } - - public SQLStatement parseShow() { - accept(Token.SHOW); - - if (lexer.token() == Token.COMMENT) { - lexer.nextToken(); - } - - boolean full = false; - if (lexer.token() == Token.FULL) { - lexer.nextToken(); - full = true; - } - - if (identifierEquals("PROCESSLIST")) { - lexer.nextToken(); - MySqlShowProcessListStatement stmt = new MySqlShowProcessListStatement(); - stmt.setFull(full); - return stmt; - } - - if (identifierEquals("COLUMNS") || identifierEquals("FIELDS")) { - lexer.nextToken(); - - MySqlShowColumnsStatement stmt = parseShowColumns(); - stmt.setFull(full); - - return stmt; - } - - if (identifierEquals("COLUMNS")) { - lexer.nextToken(); - - MySqlShowColumnsStatement stmt = parseShowColumns(); - - return stmt; - } - - if (identifierEquals(TABLES)) { - lexer.nextToken(); - - MySqlShowTablesStatement stmt = parseShowTabless(); - stmt.setFull(full); - - return stmt; - } - - if (identifierEquals("DATABASES")) { - lexer.nextToken(); - - MySqlShowDatabasesStatement stmt = parseShowDatabases(); - - return stmt; - } - - if (identifierEquals("WARNINGS")) { - lexer.nextToken(); - - MySqlShowWarningsStatement stmt = parseShowWarnings(); - - return stmt; - } - - if (identifierEquals("COUNT")) { - lexer.nextToken(); - accept(Token.LPAREN); - accept(Token.STAR); - accept(Token.RPAREN); - - if (identifierEquals(ERRORS)) { - lexer.nextToken(); - - MySqlShowErrorsStatement stmt = new MySqlShowErrorsStatement(); - stmt.setCount(true); - - return stmt; - } else { - acceptIdentifier("WARNINGS"); - - MySqlShowWarningsStatement stmt = new MySqlShowWarningsStatement(); - stmt.setCount(true); - - return stmt; - } - } - - if (identifierEquals(ERRORS)) { - lexer.nextToken(); - - MySqlShowErrorsStatement stmt = new MySqlShowErrorsStatement(); - stmt.setLimit(parseLimit()); - - return stmt; - } - - if (identifierEquals(STATUS)) { - lexer.nextToken(); - - MySqlShowStatusStatement stmt = parseShowStatus(); - - return stmt; - } - - if (identifierEquals(VARIABLES)) { - lexer.nextToken(); - - MySqlShowVariantsStatement stmt = parseShowVariants(); - - return stmt; - } - - if (identifierEquals(GLOBAL)) { - lexer.nextToken(); - - if (identifierEquals(STATUS)) { - lexer.nextToken(); - MySqlShowStatusStatement stmt = parseShowStatus(); - stmt.setGlobal(true); - return stmt; - } - - if (identifierEquals(VARIABLES)) { - lexer.nextToken(); - MySqlShowVariantsStatement stmt = parseShowVariants(); - stmt.setGlobal(true); - return stmt; - } - } - - if (identifierEquals(SESSION)) { - lexer.nextToken(); - - if (identifierEquals(STATUS)) { - lexer.nextToken(); - MySqlShowStatusStatement stmt = parseShowStatus(); - stmt.setSession(true); - return stmt; - } - - if (identifierEquals(VARIABLES)) { - lexer.nextToken(); - MySqlShowVariantsStatement stmt = parseShowVariants(); - stmt.setSession(true); - return stmt; - } - } - - if (identifierEquals("COBAR_STATUS")) { - lexer.nextToken(); - return new CobarShowStatus(); - } - - if (identifierEquals("AUTHORS")) { - lexer.nextToken(); - return new MySqlShowAuthorsStatement(); - } - - if (lexer.token() == Token.BINARY) { - lexer.nextToken(); - acceptIdentifier("LOGS"); - return new MySqlShowBinaryLogsStatement(); - } - - if (identifierEquals("MASTER")) { - lexer.nextToken(); - if (identifierEquals("LOGS")) { - lexer.nextToken(); - return new MySqlShowMasterLogsStatement(); - } - acceptIdentifier(STATUS); - return new MySqlShowMasterStatusStatement(); - } - - if (identifierEquals(CHARACTER)) { - lexer.nextToken(); - accept(Token.SET); - MySqlShowCharacterSetStatement stmt = new MySqlShowCharacterSetStatement(); - - if (lexer.token() == Token.LIKE) { - lexer.nextToken(); - stmt.setPattern(this.exprParser.expr()); - } - - if (lexer.token() == Token.WHERE) { - lexer.nextToken(); - stmt.setWhere(this.exprParser.expr()); - } - - return stmt; - } - - if (identifierEquals("COLLATION")) { - lexer.nextToken(); - MySqlShowCollationStatement stmt = new MySqlShowCollationStatement(); - - if (lexer.token() == Token.LIKE) { - lexer.nextToken(); - stmt.setPattern(this.exprParser.expr()); - } - - if (lexer.token() == Token.WHERE) { - lexer.nextToken(); - stmt.setWhere(this.exprParser.expr()); - } - - return stmt; - } - - if (identifierEquals(BINLOG)) { - lexer.nextToken(); - acceptIdentifier(EVENTS); - MySqlShowBinLogEventsStatement stmt = new MySqlShowBinLogEventsStatement(); - - if (lexer.token() == Token.IN) { - lexer.nextToken(); - stmt.setIn(this.exprParser.expr()); - } - - if (lexer.token() == Token.FROM) { - lexer.nextToken(); - stmt.setFrom(this.exprParser.expr()); - } - - stmt.setLimit(parseLimit()); - - return stmt; - } - - if (identifierEquals("CONTRIBUTORS")) { - lexer.nextToken(); - return new MySqlShowContributorsStatement(); - } - - if (lexer.token() == Token.CREATE) { - lexer.nextToken(); - - if (lexer.token() == Token.DATABASE) { - lexer.nextToken(); - - MySqlShowCreateDatabaseStatement stmt = new MySqlShowCreateDatabaseStatement(); - stmt.setDatabase(this.exprParser.name()); - return stmt; - } - - if (identifierEquals("EVENT")) { - lexer.nextToken(); - - MySqlShowCreateEventStatement stmt = new MySqlShowCreateEventStatement(); - stmt.setEventName(this.exprParser.name()); - return stmt; - } - - if (identifierEquals("FUNCTION")) { - lexer.nextToken(); - - MySqlShowCreateFunctionStatement stmt = new MySqlShowCreateFunctionStatement(); - stmt.setName(this.exprParser.name()); - return stmt; - } - - if (identifierEquals("PROCEDURE")) { - lexer.nextToken(); - - MySqlShowCreateProcedureStatement stmt = new MySqlShowCreateProcedureStatement(); - stmt.setName(this.exprParser.name()); - return stmt; - } - - if (lexer.token() == Token.TABLE) { - lexer.nextToken(); - - MySqlShowCreateTableStatement stmt = new MySqlShowCreateTableStatement(); - stmt.setName(this.exprParser.name()); - return stmt; - } - - if (lexer.token() == Token.VIEW) { - lexer.nextToken(); - - MySqlShowCreateViewStatement stmt = new MySqlShowCreateViewStatement(); - stmt.setName(this.exprParser.name()); - return stmt; - } - - if (identifierEquals("TRIGGER")) { - lexer.nextToken(); - - MySqlShowCreateTriggerStatement stmt = new MySqlShowCreateTriggerStatement(); - stmt.setName(this.exprParser.name()); - return stmt; - } - - throw new ParserException("TODO " + lexer.stringVal()); - } - - if (identifierEquals(ENGINE)) { - lexer.nextToken(); - MySqlShowEngineStatement stmt = new MySqlShowEngineStatement(); - stmt.setName(this.exprParser.name()); - stmt.setOption(MySqlShowEngineStatement.Option.valueOf(lexer.stringVal().toUpperCase())); - lexer.nextToken(); - return stmt; - } - - if (identifierEquals("STORAGE")) { - lexer.nextToken(); - acceptIdentifier(ENGINES); - MySqlShowEnginesStatement stmt = new MySqlShowEnginesStatement(); - stmt.setStorage(true); - return stmt; - } - - if (identifierEquals(ENGINES)) { - lexer.nextToken(); - MySqlShowEnginesStatement stmt = new MySqlShowEnginesStatement(); - return stmt; - } - - if (identifierEquals(EVENTS)) { - lexer.nextToken(); - MySqlShowEventsStatement stmt = new MySqlShowEventsStatement(); - - if (lexer.token() == Token.FROM || lexer.token() == Token.IN) { - lexer.nextToken(); - stmt.setSchema(this.exprParser.name()); - } - - if (lexer.token() == Token.LIKE) { - lexer.nextToken(); - stmt.setLike(this.exprParser.expr()); - } - - if (lexer.token() == Token.WHERE) { - lexer.nextToken(); - stmt.setWhere(this.exprParser.expr()); - } - return stmt; - } - - if (identifierEquals("FUNCTION")) { - lexer.nextToken(); - - if (identifierEquals("CODE")) { - lexer.nextToken(); - MySqlShowFunctionCodeStatement stmt = new MySqlShowFunctionCodeStatement(); - stmt.setName(this.exprParser.name()); - return stmt; - } - - acceptIdentifier(STATUS); - MySqlShowFunctionStatusStatement stmt = new MySqlShowFunctionStatusStatement(); - - if (lexer.token() == Token.LIKE) { - lexer.nextToken(); - stmt.setLike(this.exprParser.expr()); - } - - if (lexer.token() == Token.WHERE) { - lexer.nextToken(); - stmt.setWhere(this.exprParser.expr()); - } - return stmt; - } - - // MySqlShowFunctionStatusStatement - - if (identifierEquals(ENGINE)) { - lexer.nextToken(); - MySqlShowEngineStatement stmt = new MySqlShowEngineStatement(); - stmt.setName(this.exprParser.name()); - stmt.setOption(MySqlShowEngineStatement.Option.valueOf(lexer.stringVal().toUpperCase())); - lexer.nextToken(); - return stmt; - } - - if (identifierEquals("STORAGE")) { - lexer.nextToken(); - acceptIdentifier(ENGINES); - MySqlShowEnginesStatement stmt = new MySqlShowEnginesStatement(); - stmt.setStorage(true); - return stmt; - } - - if (identifierEquals(ENGINES)) { - lexer.nextToken(); - MySqlShowEnginesStatement stmt = new MySqlShowEnginesStatement(); - return stmt; - } - - if (identifierEquals("GRANTS")) { - lexer.nextToken(); - MySqlShowGrantsStatement stmt = new MySqlShowGrantsStatement(); - - if (lexer.token() == Token.FOR) { - lexer.nextToken(); - stmt.setUser(this.exprParser.expr()); - } - - return stmt; - } - - if (lexer.token() == Token.INDEX || identifierEquals("INDEXES")) { - lexer.nextToken(); - MySqlShowIndexesStatement stmt = new MySqlShowIndexesStatement(); - - if (lexer.token() == Token.FROM || lexer.token() == Token.IN) { - lexer.nextToken(); - SQLName table = exprParser.name(); - stmt.setTable(table); - - if (lexer.token() == Token.FROM || lexer.token() == Token.IN) { - lexer.nextToken(); - SQLName database = exprParser.name(); - stmt.setDatabase(database); - } - } - - return stmt; - } - - if (identifierEquals("KEYS")) { - lexer.nextToken(); - MySqlShowKeysStatement stmt = new MySqlShowKeysStatement(); - - if (lexer.token() == Token.FROM || lexer.token() == Token.IN) { - lexer.nextToken(); - SQLName table = exprParser.name(); - stmt.setTable(table); - - if (lexer.token() == Token.FROM || lexer.token() == Token.IN) { - lexer.nextToken(); - SQLName database = exprParser.name(); - stmt.setDatabase(database); - } - } - - return stmt; - } - - if (identifierEquals("OPEN")) { - lexer.nextToken(); - acceptIdentifier(TABLES); - MySqlShowOpenTablesStatement stmt = new MySqlShowOpenTablesStatement(); - - if (lexer.token() == Token.FROM || lexer.token() == Token.IN) { - lexer.nextToken(); - stmt.setDatabase(this.exprParser.name()); - } - - if (lexer.token() == Token.LIKE) { - lexer.nextToken(); - stmt.setLike(this.exprParser.expr()); - } - - if (lexer.token() == Token.WHERE) { - lexer.nextToken(); - stmt.setWhere(this.exprParser.expr()); - } - return stmt; - } - - if (identifierEquals("PLUGINS")) { - lexer.nextToken(); - MySqlShowPluginsStatement stmt = new MySqlShowPluginsStatement(); - return stmt; - } - - if (identifierEquals("PRIVILEGES")) { - lexer.nextToken(); - MySqlShowPrivilegesStatement stmt = new MySqlShowPrivilegesStatement(); - return stmt; - } - - if (identifierEquals("PROCEDURE")) { - lexer.nextToken(); - - if (identifierEquals("CODE")) { - lexer.nextToken(); - MySqlShowProcedureCodeStatement stmt = new MySqlShowProcedureCodeStatement(); - stmt.setName(this.exprParser.name()); - return stmt; - } - - acceptIdentifier(STATUS); - MySqlShowProcedureStatusStatement stmt = new MySqlShowProcedureStatusStatement(); - - if (lexer.token() == Token.LIKE) { - lexer.nextToken(); - stmt.setLike(this.exprParser.expr()); - } - - if (lexer.token() == Token.WHERE) { - lexer.nextToken(); - stmt.setWhere(this.exprParser.expr()); - } - return stmt; - } - - if (identifierEquals("PROCESSLIST")) { - lexer.nextToken(); - MySqlShowProcessListStatement stmt = new MySqlShowProcessListStatement(); - return stmt; - } - - if (identifierEquals("PROFILES")) { - lexer.nextToken(); - MySqlShowProfilesStatement stmt = new MySqlShowProfilesStatement(); - return stmt; - } - - if (identifierEquals("PROFILE")) { - lexer.nextToken(); - MySqlShowProfileStatement stmt = new MySqlShowProfileStatement(); - - for (;;) { - if (lexer.token() == Token.ALL) { - stmt.getTypes().add(MySqlShowProfileStatement.Type.ALL); - lexer.nextToken(); - } else if (identifierEquals("BLOCK")) { - lexer.nextToken(); - acceptIdentifier("IO"); - stmt.getTypes().add(MySqlShowProfileStatement.Type.BLOCK_IO); - } else if (identifierEquals("CONTEXT")) { - lexer.nextToken(); - acceptIdentifier("SWITCHES"); - stmt.getTypes().add(MySqlShowProfileStatement.Type.CONTEXT_SWITCHES); - } else if (identifierEquals("CPU")) { - lexer.nextToken(); - stmt.getTypes().add(MySqlShowProfileStatement.Type.CPU); - } else if (identifierEquals("IPC")) { - lexer.nextToken(); - stmt.getTypes().add(MySqlShowProfileStatement.Type.IPC); - } else if (identifierEquals("MEMORY")) { - lexer.nextToken(); - stmt.getTypes().add(MySqlShowProfileStatement.Type.MEMORY); - } else if (identifierEquals("PAGE")) { - lexer.nextToken(); - acceptIdentifier("FAULTS"); - stmt.getTypes().add(MySqlShowProfileStatement.Type.PAGE_FAULTS); - } else if (identifierEquals("SOURCE")) { - lexer.nextToken(); - stmt.getTypes().add(MySqlShowProfileStatement.Type.SOURCE); - } else if (identifierEquals("SWAPS")) { - lexer.nextToken(); - stmt.getTypes().add(MySqlShowProfileStatement.Type.SWAPS); - } else { - break; - } - - if (lexer.token() == Token.COMMA) { - lexer.nextToken(); - continue; - } - break; - } - - if (lexer.token() == Token.FOR) { - lexer.nextToken(); - acceptIdentifier("QUERY"); - stmt.setForQuery(this.exprParser.primary()); - } - - stmt.setLimit(this.parseLimit()); - - return stmt; - } - - if (identifierEquals("RELAYLOG")) { - lexer.nextToken(); - acceptIdentifier(EVENTS); - MySqlShowRelayLogEventsStatement stmt = new MySqlShowRelayLogEventsStatement(); - - if (lexer.token() == Token.IN) { - lexer.nextToken(); - stmt.setLogName(this.exprParser.primary()); - } - - if (lexer.token() == Token.FROM) { - lexer.nextToken(); - stmt.setFrom(this.exprParser.primary()); - } - - stmt.setLimit(this.parseLimit()); - - return stmt; - } - - if (identifierEquals("RELAYLOG")) { - lexer.nextToken(); - acceptIdentifier(EVENTS); - MySqlShowRelayLogEventsStatement stmt = new MySqlShowRelayLogEventsStatement(); - - if (lexer.token() == Token.IN) { - lexer.nextToken(); - stmt.setLogName(this.exprParser.primary()); - } - - if (lexer.token() == Token.FROM) { - lexer.nextToken(); - stmt.setFrom(this.exprParser.primary()); - } - - stmt.setLimit(this.parseLimit()); - - return stmt; - } - - if (identifierEquals("SLAVE")) { - lexer.nextToken(); - if (identifierEquals(STATUS)) { - lexer.nextToken(); - return new MySqlShowSlaveStatusStatement(); - } else { - acceptIdentifier("HOSTS"); - MySqlShowSlaveHostsStatement stmt = new MySqlShowSlaveHostsStatement(); - return stmt; - } - } - - if (lexer.token() == Token.TABLE) { - lexer.nextToken(); - acceptIdentifier(STATUS); - MySqlShowTableStatusStatement stmt = new MySqlShowTableStatusStatement(); - if (lexer.token() == Token.FROM || lexer.token() == Token.IN) { - lexer.nextToken(); - stmt.setDatabase(this.exprParser.name()); - } - - if (lexer.token() == Token.LIKE) { - lexer.nextToken(); - stmt.setLike(this.exprParser.expr()); - } - - if (lexer.token() == Token.WHERE) { - lexer.nextToken(); - stmt.setWhere(this.exprParser.expr()); - } - - return stmt; - } - - if (identifierEquals("TRIGGERS")) { - lexer.nextToken(); - MySqlShowTriggersStatement stmt = new MySqlShowTriggersStatement(); - - if (lexer.token() == Token.FROM) { - lexer.nextToken(); - SQLName database = exprParser.name(); - stmt.setDatabase(database); - } - - if (lexer.token() == Token.LIKE) { - lexer.nextToken(); - SQLExpr like = exprParser.expr(); - stmt.setLike(like); - } - - if (lexer.token() == Token.WHERE) { - lexer.nextToken(); - SQLExpr where = exprParser.expr(); - stmt.setWhere(where); - } - - return stmt; - } - - // MySqlShowSlaveHostsStatement - throw new ParserException("TODO " + lexer.stringVal()); - } - - private MySqlShowStatusStatement parseShowStatus() { - MySqlShowStatusStatement stmt = new MySqlShowStatusStatement(); - - if (lexer.token() == Token.LIKE) { - lexer.nextToken(); - SQLExpr like = exprParser.expr(); - stmt.setLike(like); - } - - if (lexer.token() == Token.WHERE) { - lexer.nextToken(); - SQLExpr where = exprParser.expr(); - stmt.setWhere(where); - } - - return stmt; - } - - private MySqlShowVariantsStatement parseShowVariants() { - MySqlShowVariantsStatement stmt = new MySqlShowVariantsStatement(); - - if (lexer.token() == Token.LIKE) { - lexer.nextToken(); - SQLExpr like = exprParser.expr(); - stmt.setLike(like); - } - - if (lexer.token() == Token.WHERE) { - lexer.nextToken(); - SQLExpr where = exprParser.expr(); - stmt.setWhere(where); - } - - return stmt; - } - - private MySqlShowWarningsStatement parseShowWarnings() { - MySqlShowWarningsStatement stmt = new MySqlShowWarningsStatement(); - - stmt.setLimit(parseLimit()); - - return stmt; - } - - private MySqlShowDatabasesStatement parseShowDatabases() { - MySqlShowDatabasesStatement stmt = new MySqlShowDatabasesStatement(); - - if (lexer.token() == Token.LIKE) { - lexer.nextToken(); - SQLExpr like = exprParser.expr(); - stmt.setLike(like); - } - - if (lexer.token() == Token.WHERE) { - lexer.nextToken(); - SQLExpr where = exprParser.expr(); - stmt.setWhere(where); - } - - return stmt; - } - - private MySqlShowTablesStatement parseShowTabless() { - MySqlShowTablesStatement stmt = new MySqlShowTablesStatement(); - - if (lexer.token() == Token.FROM) { - lexer.nextToken(); - SQLName database = exprParser.name(); - stmt.setDatabase(database); - } - - if (lexer.token() == Token.LIKE) { - lexer.nextToken(); - SQLExpr like = exprParser.expr(); - stmt.setLike(like); - } - - if (lexer.token() == Token.WHERE) { - lexer.nextToken(); - SQLExpr where = exprParser.expr(); - stmt.setWhere(where); - } - - return stmt; - } - - private MySqlShowColumnsStatement parseShowColumns() { - MySqlShowColumnsStatement stmt = new MySqlShowColumnsStatement(); - - if (lexer.token() == Token.FROM) { - lexer.nextToken(); - SQLName table = exprParser.name(); - stmt.setTable(table); - - if (lexer.token() == Token.FROM) { - lexer.nextToken(); - SQLName database = exprParser.name(); - stmt.setDatabase(database); - } - } - - if (lexer.token() == Token.LIKE) { - lexer.nextToken(); - SQLExpr like = exprParser.expr(); - stmt.setLike(like); - } - - if (lexer.token() == Token.WHERE) { - lexer.nextToken(); - SQLExpr where = exprParser.expr(); - stmt.setWhere(where); - } - - return stmt; - } - - public MySqlStartTransactionStatement parseStart() { - acceptIdentifier("START"); - acceptIdentifier("TRANSACTION"); - - MySqlStartTransactionStatement stmt = new MySqlStartTransactionStatement(); - - if (identifierEquals("WITH")) { - lexer.nextToken(); - acceptIdentifier("CONSISTENT"); - acceptIdentifier("SNAPSHOT"); - stmt.setConsistentSnapshot(true); - } - - if (identifierEquals("BEGIN")) { - lexer.nextToken(); - stmt.setBegin(true); - if (identifierEquals("WORK")) { - lexer.nextToken(); - stmt.setWork(true); - } - } - - return stmt; - } - - @Override - public MySqlRollbackStatement parseRollback() { - acceptIdentifier("ROLLBACK"); - - MySqlRollbackStatement stmt = new MySqlRollbackStatement(); - - if (identifierEquals("WORK")) { - lexer.nextToken(); - } - - if (lexer.token() == Token.AND) { - lexer.nextToken(); - if (lexer.token() == Token.NOT) { - lexer.nextToken(); - acceptIdentifier(CHAIN); - stmt.setChain(Boolean.FALSE); - } else { - acceptIdentifier(CHAIN); - stmt.setChain(Boolean.TRUE); - } - } - - if (lexer.token() == Token.TO) { - lexer.nextToken(); - - if (identifierEquals("SAVEPOINT")) { - lexer.nextToken(); - } - - stmt.setTo(this.exprParser.name()); - } - - return stmt; - } - - public MySqlCommitStatement parseCommit() { - acceptIdentifier("COMMIT"); - - MySqlCommitStatement stmt = new MySqlCommitStatement(); - - if (identifierEquals("WORK")) { - lexer.nextToken(); - stmt.setWork(true); - } - - if (lexer.token() == Token.AND) { - lexer.nextToken(); - if (lexer.token() == Token.NOT) { - lexer.nextToken(); - acceptIdentifier(CHAIN); - stmt.setChain(Boolean.FALSE); - } else { - acceptIdentifier(CHAIN); - stmt.setChain(Boolean.TRUE); - } - } - - return stmt; - } - - public MySqlReplaceStatement parseReplicate() { - MySqlReplaceStatement stmt = new MySqlReplaceStatement(); - - accept(Token.REPLACE); - - if (lexer.token() == Token.COMMENT) { - lexer.nextToken(); - } - - if (identifierEquals(LOW_PRIORITY)) { - stmt.setLowPriority(true); - lexer.nextToken(); - } - - if (identifierEquals(DELAYED)) { - stmt.setDelayed(true); - lexer.nextToken(); - } - - if (lexer.token() == Token.INTO) { - lexer.nextToken(); - } - - SQLName tableName = exprParser.name(); - stmt.setTableName(tableName); - - if (lexer.token() == Token.LPAREN) { - lexer.nextToken(); - if (lexer.token() == Token.SELECT) { - SQLQueryExpr queryExpr = (SQLQueryExpr) this.exprParser.expr(); - stmt.setQuery(queryExpr); - } else { - this.exprParser.exprList(stmt.getColumns()); - } - accept(Token.RPAREN); - } - - if (lexer.token() == Token.VALUES || identifierEquals("VALUE")) { - lexer.nextToken(); - - parseValueClause(stmt.getValuesList(), 0); - } else if (lexer.token() == Token.SELECT) { - SQLQueryExpr queryExpr = (SQLQueryExpr) this.exprParser.expr(); - stmt.setQuery(queryExpr); - } else if (lexer.token() == Token.SET) { - lexer.nextToken(); - - SQLInsertStatement.ValuesClause values = new SQLInsertStatement.ValuesClause(); - stmt.getValuesList().add(values); - for (;;) { - stmt.getColumns().add(this.exprParser.name()); - if (lexer.token() == Token.COLONEQ) { - lexer.nextToken(); - } else { - accept(Token.EQ); - } - values.getValues().add(this.exprParser.expr()); - - if (lexer.token() == (Token.COMMA)) { - lexer.nextToken(); - continue; - } - - break; - } - } else if (lexer.token() == Token.LPAREN) { - lexer.nextToken(); - SQLQueryExpr queryExpr = (SQLQueryExpr) this.exprParser.expr(); - stmt.setQuery(queryExpr); - accept(Token.RPAREN); - } - - return stmt; - } - - protected SQLStatement parseLoad() { - acceptIdentifier("LOAD"); - - if (identifierEquals("DATA")) { - SQLStatement stmt = parseLoadDataInFile(); - return stmt; - } - - if (identifierEquals("XML")) { - SQLStatement stmt = parseLoadXml(); - return stmt; - } - - throw new ParserException("TODO"); - } - - protected MySqlLoadXmlStatement parseLoadXml() { - acceptIdentifier("XML"); - - MySqlLoadXmlStatement stmt = new MySqlLoadXmlStatement(); - - if (identifierEquals(LOW_PRIORITY)) { - stmt.setLowPriority(true); - lexer.nextToken(); - } - - if (identifierEquals("CONCURRENT")) { - stmt.setConcurrent(true); - lexer.nextToken(); - } - - if (identifierEquals(LOCAL)) { - stmt.setLocal(true); - lexer.nextToken(); - } - - acceptIdentifier("INFILE"); - - SQLLiteralExpr fileName = (SQLLiteralExpr) exprParser.expr(); - stmt.setFileName(fileName); - - if (lexer.token() == Token.REPLACE) { - stmt.setReplicate(true); - lexer.nextToken(); - } - - if (identifierEquals(IGNORE)) { - stmt.setIgnore(true); - lexer.nextToken(); - } - - accept(Token.INTO); - accept(Token.TABLE); - - SQLName tableName = exprParser.name(); - stmt.setTableName(tableName); - - if (identifierEquals(CHARACTER)) { - lexer.nextToken(); - accept(Token.SET); - - if (lexer.token() != Token.LITERAL_CHARS) { - throw new ParserException("syntax error, illegal charset"); - } - - String charset = lexer.stringVal(); - lexer.nextToken(); - stmt.setCharset(charset); - } - - if (identifierEquals("ROWS")) { - lexer.nextToken(); - accept(Token.IDENTIFIED); - accept(Token.BY); - SQLExpr rowsIdentifiedBy = exprParser.expr(); - stmt.setRowsIdentifiedBy(rowsIdentifiedBy); - } - - if (identifierEquals(IGNORE)) { - throw new ParserException("TODO"); - } - - if (lexer.token() == Token.SET) { - throw new ParserException("TODO"); - } - - return stmt; - } - - protected MySqlLoadDataInFileStatement parseLoadDataInFile() { - acceptIdentifier("DATA"); - - MySqlLoadDataInFileStatement stmt = new MySqlLoadDataInFileStatement(); - - if (identifierEquals(LOW_PRIORITY)) { - stmt.setLowPriority(true); - lexer.nextToken(); - } - - if (identifierEquals("CONCURRENT")) { - stmt.setConcurrent(true); - lexer.nextToken(); - } - - if (identifierEquals(LOCAL)) { - stmt.setLocal(true); - lexer.nextToken(); - } - - acceptIdentifier("INFILE"); - - SQLLiteralExpr fileName = (SQLLiteralExpr) exprParser.expr(); - stmt.setFileName(fileName); - - if (lexer.token() == Token.REPLACE) { - stmt.setReplicate(true); - lexer.nextToken(); - } - - if (identifierEquals(IGNORE)) { - stmt.setIgnore(true); - lexer.nextToken(); - } - - accept(Token.INTO); - accept(Token.TABLE); - - SQLName tableName = exprParser.name(); - stmt.setTableName(tableName); - - if (identifierEquals(CHARACTER)) { - lexer.nextToken(); - accept(Token.SET); - - if (lexer.token() != Token.LITERAL_CHARS) { - throw new ParserException("syntax error, illegal charset"); - } - - String charset = lexer.stringVal(); - lexer.nextToken(); - stmt.setCharset(charset); - } - - if (identifierEquals("FIELDS") || identifierEquals("COLUMNS")) { - throw new ParserException("TODO"); - } - - if (identifierEquals("LINES")) { - throw new ParserException("TODO"); - } - - if (identifierEquals(IGNORE)) { - throw new ParserException("TODO"); - } - - if (lexer.token() == Token.SET) { - throw new ParserException("TODO"); - } - - return stmt; - } - - public MySqlPrepareStatement parsePrepare() { - acceptIdentifier("PREPARE"); - - SQLName name = exprParser.name(); - accept(Token.FROM); - SQLExpr from = exprParser.expr(); - - return new MySqlPrepareStatement(name, from); - } - - public MySqlExecuteStatement parseExecute() { - acceptIdentifier("EXECUTE"); - - MySqlExecuteStatement stmt = new MySqlExecuteStatement(); - - SQLName statementName = exprParser.name(); - stmt.setStatementName(statementName); - - if (identifierEquals("USING")) { - lexer.nextToken(); - exprParser.exprList(stmt.getParameters()); - } - - return stmt; - } - - public SQLInsertStatement parseInsert() { - MySqlInsertStatement insertStatement = new MySqlInsertStatement(); - - if (lexer.token() == Token.INSERT) { - lexer.nextToken(); - - if (identifierEquals(LOW_PRIORITY)) { - insertStatement.setLowPriority(true); - lexer.nextToken(); - } - - if (identifierEquals(DELAYED)) { - insertStatement.setDelayed(true); - lexer.nextToken(); - } - - if (identifierEquals("HIGH_PRIORITY")) { - insertStatement.setHighPriority(true); - lexer.nextToken(); - } - - if (identifierEquals(IGNORE)) { - insertStatement.setIgnore(true); - lexer.nextToken(); - } - - if (lexer.token() == Token.INTO) { - lexer.nextToken(); - } - - SQLName tableName = this.exprParser.name(); - insertStatement.setTableName(tableName); - - if (lexer.token() == Token.IDENTIFIER && !identifierEquals("VALUE")) { - insertStatement.setAlias(lexer.stringVal()); - lexer.nextToken(); - } - - } - - int columnSize = 0; - if (lexer.token() == (Token.LPAREN)) { - lexer.nextToken(); - if (lexer.token() == (Token.SELECT)) { - SQLSelect select = this.exprParser.createSelectParser().select(); - select.setParent(insertStatement); - insertStatement.setQuery(select); - } else { - this.exprParser.exprList(insertStatement.getColumns()); - columnSize = insertStatement.getColumns().size(); - } - accept(Token.RPAREN); - } - - if (lexer.token() == Token.VALUES || identifierEquals("VALUE")) { - lexer.nextTokenLParen(); - parseValueClause(insertStatement.getValuesList(), columnSize); - } else if (lexer.token() == Token.SET) { - lexer.nextToken(); - - SQLInsertStatement.ValuesClause values = new SQLInsertStatement.ValuesClause(); - insertStatement.getValuesList().add(values); - - for (;;) { - SQLName name = this.exprParser.name(); - insertStatement.getColumns().add(name); - if (lexer.token() == Token.EQ) { - lexer.nextToken(); - } else { - accept(Token.COLONEQ); - } - values.getValues().add(this.exprParser.expr()); - - if (lexer.token() == Token.COMMA) { - lexer.nextToken(); - continue; - } - - break; - } - - } else if (lexer.token() == (Token.SELECT)) { - SQLSelect select = this.exprParser.createSelectParser().select(); - select.setParent(insertStatement); - insertStatement.setQuery(select); - } else if (lexer.token() == (Token.LPAREN)) { - lexer.nextToken(); - SQLSelect select = this.exprParser.createSelectParser().select(); - select.setParent(insertStatement); - insertStatement.setQuery(select); - accept(Token.RPAREN); - } - - if (lexer.token() == Token.ON) { - lexer.nextToken(); - acceptIdentifier("DUPLICATE"); - accept(Token.KEY); - accept(Token.UPDATE); - - exprParser.exprList(insertStatement.getDuplicateKeyUpdate()); - } - - return insertStatement; - } - - private void parseValueClause(List valueClauseList, int columnSize) { - for (;;) { - if (lexer.token() != Token.LPAREN) { - throw new ParserException("syntax error, expect ')'"); - } - lexer.nextTokenValue(); - - if (lexer.token() != Token.RPAREN) { - List valueExprList; - if (columnSize > 0) { - valueExprList = new ArrayList(columnSize); - } else { - valueExprList = new ArrayList(); - } - - for (;;) { - SQLExpr expr; - if (lexer.token() == Token.LITERAL_INT) { - expr = new SQLIntegerExpr(lexer.integerValue()); - lexer.nextTokenComma(); - } else if (lexer.token() == Token.LITERAL_CHARS) { - expr = new SQLCharExpr(lexer.stringVal()); - lexer.nextTokenComma(); - } else if (lexer.token() == Token.LITERAL_CHARS) { - expr = new SQLCharExpr(lexer.stringVal()); - lexer.nextTokenComma(); - } else { - expr = exprParser.expr(); - } - - if (lexer.token() == Token.COMMA) { - valueExprList.add(expr); - lexer.nextTokenValue(); - continue; - } else if (lexer.token() == Token.RPAREN) { - valueExprList.add(expr); - break; - } else { - expr = this.exprParser.primaryRest(expr); - valueExprList.add(expr); - if (lexer.token() == Token.COMMA) { - lexer.nextToken(); - continue; - } else { - break; - } - } - } - - SQLInsertStatement.ValuesClause values = new SQLInsertStatement.ValuesClause(valueExprList); - valueClauseList.add(values); - } else { - SQLInsertStatement.ValuesClause values = new SQLInsertStatement.ValuesClause(new ArrayList(0)); - valueClauseList.add(values); - } - - if (lexer.token() != Token.RPAREN) { - throw new ParserException("syntax error"); - } - - lexer.nextTokenComma(); - if (lexer.token() == Token.COMMA) { - lexer.nextTokenLParen(); - continue; - } else { - break; - } - } - } - - public SQLStatement parseDropUser() { - acceptIdentifier(USER); - - MySqlDropUser stmt = new MySqlDropUser(); - for (;;) { - SQLExpr expr = this.exprParser.expr(); - stmt.getUsers().add(expr); - if (lexer.token() == Token.COMMA) { - lexer.nextToken(); - continue; - } - break; - } - - return stmt; - } - - protected SQLDropTableStatement parseDropTable(boolean acceptDrop) { - if (acceptDrop) { - accept(Token.DROP); - } - - MySqlDropTableStatement stmt = new MySqlDropTableStatement(); - - if (identifierEquals(TEMPORARY)) { - lexer.nextToken(); - stmt.setTemporary(true); - } - - accept(Token.TABLE); - - if (lexer.token() == Token.IF) { - lexer.nextToken(); - accept(Token.EXISTS); - stmt.setIfExists(true); - } - - for (;;) { - SQLName name = this.exprParser.name(); - stmt.addTableSource(name); - if (lexer.token() == Token.COMMA) { - lexer.nextToken(); - continue; - } - break; - } - - if (identifierEquals(RESTRICT)) { - stmt.setOption(RESTRICT); - lexer.nextToken(); - } else if (identifierEquals(CASCADE)) { - stmt.setOption(CASCADE); - lexer.nextToken(); - } - - return stmt; - } - - protected SQLDropViewStatement parseDropView(boolean acceptDrop) { - if (acceptDrop) { - accept(Token.DROP); - } - - MySqlDropViewStatement stmt = new MySqlDropViewStatement(); - - accept(Token.VIEW); - - if (lexer.token() == Token.IF) { - lexer.nextToken(); - accept(Token.EXISTS); - stmt.setIfExists(true); - } - - for (;;) { - SQLName name = this.exprParser.name(); - stmt.addTableSource(name); - if (lexer.token() == Token.COMMA) { - lexer.nextToken(); - continue; - } - break; - } - - if (identifierEquals(RESTRICT)) { - stmt.setOption(RESTRICT); - lexer.nextToken(); - } else if (identifierEquals(CASCADE)) { - stmt.setOption(CASCADE); - lexer.nextToken(); - } - - return stmt; - } - - public SQLSelectParser createSQLSelectParser() { - return new MySqlSelectParser(this.exprParser); - } - - public SQLStatement parseSet() { - accept(Token.SET); - - Boolean global = null; - if (identifierEquals(GLOBAL)) { - global = Boolean.TRUE; - lexer.nextToken(); - } else if (identifierEquals(SESSION)) { - global = Boolean.FALSE; - lexer.nextToken(); - } - - if (identifierEquals("TRANSACTION")) { - lexer.nextToken(); - acceptIdentifier("ISOLATION"); - acceptIdentifier("LEVEL"); - - MySqlSetTransactionIsolationLevelStatement stmt = new MySqlSetTransactionIsolationLevelStatement(); - stmt.setGlobal(global); - - if (identifierEquals(READ)) { - lexer.nextToken(); - - if (identifierEquals("UNCOMMITTED")) { - stmt.setLevel("READ UNCOMMITTED"); - lexer.nextToken(); - } else if (identifierEquals(WRITE)) { - stmt.setLevel("READ WRITE"); - lexer.nextToken(); - } else if (identifierEquals("ONLY")) { - stmt.setLevel("READ ONLY"); - lexer.nextToken(); - } else if (identifierEquals("COMMITTED")) { - stmt.setLevel("READ COMMITTED"); - lexer.nextToken(); - } else { - throw new ParserException("UNKOWN TRANSACTION LEVEL : " + lexer.stringVal()); - } - } else if (identifierEquals("SERIALIZABLE")) { - stmt.setLevel("SERIALIZABLE"); - lexer.nextToken(); - } else if (identifierEquals("REPEATABLE")) { - lexer.nextToken(); - if (identifierEquals(READ)) { - stmt.setLevel("REPEATABLE READ"); - lexer.nextToken(); - } else { - throw new ParserException("UNKOWN TRANSACTION LEVEL : " + lexer.stringVal()); - } - } else { - throw new ParserException("UNKOWN TRANSACTION LEVEL : " + lexer.stringVal()); - } - - return stmt; - } else if (identifierEquals("NAMES")) { - lexer.nextToken(); - - MySqlSetNamesStatement stmt = new MySqlSetNamesStatement(); - if (lexer.token() == Token.DEFAULT) { - lexer.nextToken(); - stmt.setDefault(true); - } else { - String charSet = lexer.stringVal(); - stmt.setCharSet(charSet); - lexer.nextToken(); - if (identifierEquals(COLLATE2)) { - lexer.nextToken(); - - String collate = lexer.stringVal(); - stmt.setCollate(collate); - lexer.nextToken(); - } - } - return stmt; - } else if (identifierEquals(CHARACTER)) { - lexer.nextToken(); - - accept(Token.SET); - - MySqlSetCharSetStatement stmt = new MySqlSetCharSetStatement(); - if (lexer.token() == Token.DEFAULT) { - lexer.nextToken(); - stmt.setDefault(true); - } else { - String charSet = lexer.stringVal(); - stmt.setCharSet(charSet); - lexer.nextToken(); - if (identifierEquals(COLLATE2)) { - lexer.nextToken(); - - String collate = lexer.stringVal(); - stmt.setCollate(collate); - lexer.nextToken(); - } - } - return stmt; - } else { - SQLSetStatement stmt = new SQLSetStatement(); - - parseAssignItems(stmt.getItems()); - - if (global != null && global.booleanValue()) { - SQLVariantRefExpr varRef = (SQLVariantRefExpr) stmt.getItems().get(0).getTarget(); - varRef.setGlobal(true); - } - - return stmt; - } - } - - public Limit parseLimit() { - return ((MySqlExprParser) this.exprParser).parseLimit(); - } - - public SQLStatement parseAlter() { - accept(Token.ALTER); - - boolean ignore = false; - - if (identifierEquals(IGNORE)) { - ignore = true; - lexer.nextToken(); - } - - if (lexer.token() == Token.TABLE) { - lexer.nextToken(); - - MySqlAlterTableStatement stmt = new MySqlAlterTableStatement(); - stmt.setIgnore(ignore); - stmt.setName(this.exprParser.name()); - - for (;;) { - if (lexer.token() == Token.DROP) { - parseAlterDrop(stmt); - } else if (identifierEquals("ADD")) { - lexer.nextToken(); - - if (identifierEquals("COLUMN")) { - lexer.nextToken(); - MySqlAlterTableAddColumn item = new MySqlAlterTableAddColumn(); - SQLColumnDefinition columnDef = this.exprParser.parseColumn(); - item.getColumns().add(columnDef); - if (identifierEquals("AFTER")) { - lexer.nextToken(); - item.setAfterColumn(this.exprParser.name()); - } else if (identifierEquals("FIRST")) { - lexer.nextToken(); - if (lexer.token() == Token.IDENTIFIER) { - item.setFirstColumn(this.exprParser.name()); - } else { - item.setFirst(true); - } - } - stmt.getItems().add(item); - } else if (lexer.token() == Token.INDEX) { - lexer.nextToken(); - MySqlAlterTableAddIndex item = new MySqlAlterTableAddIndex(); - - if (lexer.token() == Token.LPAREN) { - lexer.nextToken(); - } else { - item.setName(this.exprParser.name()); - accept(Token.LPAREN); - } - - for (;;) { - SQLSelectOrderByItem column = this.exprParser.parseSelectOrderByItem(); - item.getItems().add(column); - if (lexer.token() == Token.COMMA) { - lexer.nextToken(); - continue; - } - break; - } - accept(Token.RPAREN); - - stmt.getItems().add(item); - } else if (lexer.token() == Token.UNIQUE) { - lexer.nextToken(); - - if (lexer.token() == Token.INDEX) { - lexer.nextToken(); - } - - MySqlAlterTableAddUnique item = new MySqlAlterTableAddUnique(); - - if (lexer.token() == Token.LPAREN) { - lexer.nextToken(); - } else { - item.setName(this.exprParser.name()); - accept(Token.LPAREN); - } - - for (;;) { - SQLSelectOrderByItem column = this.exprParser.parseSelectOrderByItem(); - item.getItems().add(column); - if (lexer.token() == Token.COMMA) { - lexer.nextToken(); - continue; - } - break; - } - accept(Token.RPAREN); - - stmt.getItems().add(item); - } else if (lexer.token() == Token.PRIMARY) { - SQLPrimaryKey primaryKey = ((MySqlExprParser) this.exprParser).parsePrimaryKey(); - SQLAlterTableAddPrimaryKey item = new SQLAlterTableAddPrimaryKey(); - item.setPrimaryKey(primaryKey); - stmt.getItems().add(item); - } else if (lexer.token() == Token.KEY) { - throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); - } else if (lexer.token() == Token.CONSTRAINT) { - lexer.nextToken(); - SQLName constraintName = this.exprParser.name(); - - if (lexer.token() == Token.PRIMARY) { - SQLPrimaryKey primaryKey = ((MySqlExprParser) this.exprParser).parsePrimaryKey(); - - primaryKey.setName(constraintName); - - SQLAlterTableAddPrimaryKey item = new SQLAlterTableAddPrimaryKey(); - item.setPrimaryKey(primaryKey); - stmt.getItems().add(item); - } else if (lexer.token() == Token.FOREIGN) { - MySqlForeignKey fk = this.getExprParser().parseForeignKey(); - fk.setName(constraintName); - - SQLAlterTableAddForeignKey item = new SQLAlterTableAddForeignKey(fk); - stmt.getItems().add(item); - } else { - throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); - } - } else if (identifierEquals(FULLTEXT)) { - throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); - } else if (identifierEquals(SPATIAL)) { - throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); - } else { - MySqlAlterTableAddColumn item = new MySqlAlterTableAddColumn(); - SQLColumnDefinition columnDef = this.exprParser.parseColumn(); - item.getColumns().add(columnDef); - if (identifierEquals("AFTER")) { - lexer.nextToken(); - item.setAfterColumn(this.exprParser.name()); - } - stmt.getItems().add(item); - } - } else if (lexer.token() == Token.ALTER) { - lexer.nextToken(); - if (identifierEquals("COLUMN")) { - lexer.nextToken(); - } - - SQLAlterTableAlterColumn alterColumn = new SQLAlterTableAlterColumn(); - SQLColumnDefinition columnDef = this.exprParser.parseColumn(); - alterColumn.setColumn(columnDef); - - stmt.getItems().add(alterColumn); - } else if (identifierEquals("CHANGE")) { - lexer.nextToken(); - if (identifierEquals("COLUMN")) { - lexer.nextToken(); - } - MySqlAlterTableChangeColumn item = new MySqlAlterTableChangeColumn(); - item.setColumnName(this.exprParser.name()); - item.setNewColumnDefinition(this.exprParser.parseColumn()); - if (identifierEquals("AFTER")) { - lexer.nextToken(); - item.setAfterColumn(this.exprParser.name()); - } else if (identifierEquals("FIRST")) { - lexer.nextToken(); - if (lexer.token() == Token.IDENTIFIER) { - item.setFirstColumn(this.exprParser.name()); - } else { - item.setFirst(true); - } - } - stmt.getItems().add(item); - } else if (identifierEquals("MODIFY")) { - lexer.nextToken(); - if (identifierEquals("COLUMN")) { - lexer.nextToken(); - } - MySqlAlterTableModifyColumn item = new MySqlAlterTableModifyColumn(); - item.setNewColumnDefinition(this.exprParser.parseColumn()); - if (identifierEquals("AFTER")) { - lexer.nextToken(); - item.setAfterColumn(this.exprParser.name()); - } else if (identifierEquals("FIRST")) { - lexer.nextToken(); - if (lexer.token() == Token.IDENTIFIER) { - item.setFirstColumn(this.exprParser.name()); - } else { - item.setFirst(true); - } - } - stmt.getItems().add(item); - } else if (identifierEquals("DISABLE")) { - lexer.nextToken(); - - if (lexer.token() == Token.CONSTRAINT) { - lexer.nextToken(); - SQLAlterTableDisableConstraint item = new SQLAlterTableDisableConstraint(); - item.setConstraintName(this.exprParser.name()); - stmt.getItems().add(item); - } else { - acceptIdentifier("KEYS"); - SQLAlterTableDisableKeys item = new SQLAlterTableDisableKeys(); - stmt.getItems().add(item); - } - } else if (identifierEquals("ENABLE")) { - lexer.nextToken(); - if (lexer.token() == Token.CONSTRAINT) { - lexer.nextToken(); - SQLAlterTableEnableConstraint item = new SQLAlterTableEnableConstraint(); - item.setConstraintName(this.exprParser.name()); - stmt.getItems().add(item); - } else { - acceptIdentifier("KEYS"); - SQLAlterTableEnableKeys item = new SQLAlterTableEnableKeys(); - stmt.getItems().add(item); - } - } else if (identifierEquals("RENAME")) { - lexer.nextToken(); - MySqlRenameTableStatement renameStmt = new MySqlRenameTableStatement(); - MySqlRenameTableStatement.Item item = new MySqlRenameTableStatement.Item(); - item.setName(stmt.getTableSource().getExpr()); - item.setTo(this.exprParser.name()); - renameStmt.getItems().add(item); - - return renameStmt; - } else if (lexer.token() == Token.ORDER) { - throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); - } else if (identifierEquals("CONVERT")) { - throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); - } else if (lexer.token() == Token.DEFAULT) { - throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); - } else if (identifierEquals("DISCARD")) { - lexer.nextToken(); - acceptIdentifier("TABLESPACE"); - MySqlAlterTableDiscardTablespace item = new MySqlAlterTableDiscardTablespace(); - stmt.getItems().add(item); - } else if (identifierEquals("IMPORT")) { - lexer.nextToken(); - acceptIdentifier("TABLESPACE"); - MySqlAlterTableImportTablespace item = new MySqlAlterTableImportTablespace(); - stmt.getItems().add(item); - } else if (identifierEquals("FORCE")) { - throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); - } else if (identifierEquals("TRUNCATE")) { - throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); - } else if (identifierEquals("COALESCE")) { - throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); - } else if (identifierEquals("REORGANIZE")) { - throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); - } else if (identifierEquals("EXCHANGE")) { - throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); - } else if (identifierEquals("ANALYZE")) { - throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); - } else if (identifierEquals("CHECK")) { - throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); - } else if (identifierEquals("OPTIMIZE")) { - throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); - } else if (identifierEquals("REBUILD")) { - throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); - } else if (identifierEquals("REPAIR")) { - throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); - } else if (identifierEquals("REMOVE")) { - throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); - } else if (identifierEquals(ENGINE)) { - lexer.nextToken(); - accept(Token.EQ); - stmt.getItems().add(new MySqlAlterTableOption(ENGINE, lexer.stringVal())); - lexer.nextToken(); - } else if (identifierEquals(AUTO_INCREMENT)) { - lexer.nextToken(); - accept(Token.EQ); - stmt.getItems().add(new MySqlAlterTableOption(AUTO_INCREMENT, lexer.integerValue())); - lexer.nextToken(); - } else if (identifierEquals(COLLATE2)) { - lexer.nextToken(); - accept(Token.EQ); - stmt.getItems().add(new MySqlAlterTableOption(COLLATE2, lexer.stringVal())); - lexer.nextToken(); - } else if (identifierEquals("PACK_KEYS")) { - lexer.nextToken(); - accept(Token.EQ); - if (identifierEquals("PACK")) { - lexer.nextToken(); - accept(Token.ALL); - stmt.getItems().add(new MySqlAlterTableOption("PACK_KEYS", "PACK ALL")); - } else { - stmt.getItems().add(new MySqlAlterTableOption("PACK_KEYS", lexer.stringVal())); - lexer.nextToken(); - } - } else if (identifierEquals(CHARACTER)) { - lexer.nextToken(); - accept(Token.SET); - accept(Token.EQ); - MySqlAlterTableCharacter item = new MySqlAlterTableCharacter(); - item.setCharacterSet(this.exprParser.primary()); - if (lexer.token() == Token.COMMA) { - lexer.nextToken(); - acceptIdentifier(COLLATE2); - accept(Token.EQ); - item.setCollate(this.exprParser.primary()); - } - stmt.getItems().add(item); - } else { - break; - } - - if (lexer.token() == Token.COMMA) { - lexer.nextToken(); - continue; - } else { - break; - } - } - - return stmt; - } - throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); - } - - public void parseAlterDrop(SQLAlterTableStatement stmt) { - lexer.nextToken(); - if (lexer.token() == Token.INDEX) { - lexer.nextToken(); - SQLName indexName = this.exprParser.name(); - SQLAlterTableDropIndex item = new SQLAlterTableDropIndex(); - item.setIndexName(indexName); - stmt.getItems().add(item); - } else if (lexer.token() == Token.FOREIGN) { - lexer.nextToken(); - accept(Token.KEY); - SQLName indexName = this.exprParser.name(); - SQLAlterTableDropForeinKey item = new SQLAlterTableDropForeinKey(); - item.setIndexName(indexName); - stmt.getItems().add(item); - } else if (lexer.token() == Token.PRIMARY) { - lexer.nextToken(); - accept(Token.KEY); - SQLAlterTableDropPrimaryKey item = new SQLAlterTableDropPrimaryKey(); - stmt.getItems().add(item); - } else if (lexer.token() == Token.CONSTRAINT) { - lexer.nextToken(); - SQLAlterTableDropConstraint item = new SQLAlterTableDropConstraint(); - item.setConstraintName(this.exprParser.name()); - stmt.getItems().add(item); - } else if (identifierEquals("COLUMN")) { - lexer.nextToken(); - SQLAlterTableDropColumnItem item = new SQLAlterTableDropColumnItem(); - item.setColumnName(this.exprParser.name()); - stmt.getItems().add(item); - } else { - super.parseAlterDrop(stmt); - } - } - - public SQLStatement parseRename() { - MySqlRenameTableStatement stmt = new MySqlRenameTableStatement(); - - acceptIdentifier("RENAME"); - - accept(Token.TABLE); - - for (;;) { - MySqlRenameTableStatement.Item item = new MySqlRenameTableStatement.Item(); - item.setName(this.exprParser.name()); - accept(Token.TO); - item.setTo(this.exprParser.name()); - - stmt.getItems().add(item); - - if (lexer.token() == Token.COMMA) { - lexer.nextToken(); - continue; - } - - break; - } - - return stmt; - } - - public SQLStatement parseCreateDatabase() { - if (lexer.token() == Token.CREATE) { - lexer.nextToken(); - } - - accept(Token.DATABASE); - - SQLCreateDatabaseStatement stmt = new SQLCreateDatabaseStatement(); - stmt.setName(this.exprParser.name()); - - if (lexer.token() == Token.DEFAULT) { - lexer.nextToken(); - } - - return stmt; - } - - protected void parseUpdateSet(SQLUpdateStatement update) { - accept(Token.SET); - - for (;;) { - SQLUpdateSetItem item = new SQLUpdateSetItem(); - - if (lexer.token() == (Token.LPAREN)) { - lexer.nextToken(); - SQLListExpr list = new SQLListExpr(); - this.exprParser.exprList(list.getItems()); - accept(Token.RPAREN); - item.setColumn(list); - } else { - item.setColumn(this.exprParser.primary()); - } - if (lexer.token() == Token.COLONEQ) { - lexer.nextToken(); - } else { - accept(Token.EQ); - } - item.setValue(this.exprParser.expr()); - update.getItems().add(item); - - if (lexer.token() != Token.COMMA) { - break; - } - - lexer.nextToken(); - } - } - - public MySqlExprParser getExprParser() { - return (MySqlExprParser) exprParser; - } -} +/* + * Copyright 1999-2011 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 java.util.ArrayList; +import java.util.List; + +import com.alibaba.druid.sql.ast.SQLCommentHint; +import com.alibaba.druid.sql.ast.SQLExpr; +import com.alibaba.druid.sql.ast.SQLName; +import com.alibaba.druid.sql.ast.SQLOrderBy; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.ast.expr.SQLCharExpr; +import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr; +import com.alibaba.druid.sql.ast.expr.SQLListExpr; +import com.alibaba.druid.sql.ast.expr.SQLLiteralExpr; +import com.alibaba.druid.sql.ast.expr.SQLQueryExpr; +import com.alibaba.druid.sql.ast.expr.SQLVariantRefExpr; +import com.alibaba.druid.sql.ast.statement.SQLAlterTableAddForeignKey; +import com.alibaba.druid.sql.ast.statement.SQLAlterTableAddPrimaryKey; +import com.alibaba.druid.sql.ast.statement.SQLAlterTableAlterColumn; +import com.alibaba.druid.sql.ast.statement.SQLAlterTableDisableConstraint; +import com.alibaba.druid.sql.ast.statement.SQLAlterTableDisableKeys; +import com.alibaba.druid.sql.ast.statement.SQLAlterTableDropColumnItem; +import com.alibaba.druid.sql.ast.statement.SQLAlterTableDropConstraint; +import com.alibaba.druid.sql.ast.statement.SQLAlterTableDropForeinKey; +import com.alibaba.druid.sql.ast.statement.SQLAlterTableDropIndex; +import com.alibaba.druid.sql.ast.statement.SQLAlterTableDropPrimaryKey; +import com.alibaba.druid.sql.ast.statement.SQLAlterTableEnableConstraint; +import com.alibaba.druid.sql.ast.statement.SQLAlterTableEnableKeys; +import com.alibaba.druid.sql.ast.statement.SQLAlterTableStatement; +import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition; +import com.alibaba.druid.sql.ast.statement.SQLCreateDatabaseStatement; +import com.alibaba.druid.sql.ast.statement.SQLCreateTableStatement; +import com.alibaba.druid.sql.ast.statement.SQLDropTableStatement; +import com.alibaba.druid.sql.ast.statement.SQLDropViewStatement; +import com.alibaba.druid.sql.ast.statement.SQLInsertStatement; +import com.alibaba.druid.sql.ast.statement.SQLInsertStatement.ValuesClause; +import com.alibaba.druid.sql.ast.statement.SQLPrimaryKey; +import com.alibaba.druid.sql.ast.statement.SQLSelect; +import com.alibaba.druid.sql.ast.statement.SQLSelectOrderByItem; +import com.alibaba.druid.sql.ast.statement.SQLSelectStatement; +import com.alibaba.druid.sql.ast.statement.SQLSetStatement; +import com.alibaba.druid.sql.ast.statement.SQLTableSource; +import com.alibaba.druid.sql.ast.statement.SQLUpdateSetItem; +import com.alibaba.druid.sql.ast.statement.SQLUpdateStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.MySqlForeignKey; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.CobarShowStatus; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableAddColumn; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableAddIndex; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableAddUnique; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableChangeColumn; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableCharacter; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableDiscardTablespace; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableImportTablespace; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableModifyColumn; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableOption; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlBinlogStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCommitStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateIndexStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateTableStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateUserStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlDeleteStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlDescribeStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlDropTableStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlDropUser; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlDropViewStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlExecuteStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlHelpStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlInsertStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlKillStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlLoadDataInFileStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlLoadXmlStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlLockTableStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlLockTableStatement.LockType; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlPrepareStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlRenameTableStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlReplaceStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlResetStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlRollbackStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock.Limit; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSetCharSetStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSetNamesStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSetTransactionIsolationLevelStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowAuthorsStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowBinLogEventsStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowBinaryLogsStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowCharacterSetStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowCollationStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowColumnsStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowContributorsStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowCreateDatabaseStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowCreateEventStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowCreateFunctionStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowCreateProcedureStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowCreateTableStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowCreateTriggerStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowCreateViewStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowDatabasesStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowEngineStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowEnginesStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowErrorsStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowEventsStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowFunctionCodeStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowFunctionStatusStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowGrantsStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowIndexesStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowKeysStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowMasterLogsStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowMasterStatusStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowOpenTablesStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowPluginsStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowPrivilegesStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowProcedureCodeStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowProcedureStatusStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowProcessListStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowProfileStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowProfilesStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowRelayLogEventsStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowSlaveHostsStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowSlaveStatusStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowStatusStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowTableStatusStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowTablesStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowTriggersStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowVariantsStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowWarningsStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlStartTransactionStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlUnlockTablesStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlUpdateStatement; +import com.alibaba.druid.sql.parser.Lexer; +import com.alibaba.druid.sql.parser.ParserException; +import com.alibaba.druid.sql.parser.SQLSelectParser; +import com.alibaba.druid.sql.parser.SQLStatementParser; +import com.alibaba.druid.sql.parser.Token; + +public class MySqlStatementParser extends SQLStatementParser { + + private static final String AUTO_INCREMENT = "AUTO_INCREMENT"; + private static final String COLLATE2 = "COLLATE"; + private static final String CASCADE = "CASCADE"; + private static final String RESTRICT = "RESTRICT"; + private static final String CHAIN = "CHAIN"; + private static final String ENGINES = "ENGINES"; + private static final String ENGINE = "ENGINE"; + private static final String BINLOG = "BINLOG"; + private static final String EVENTS = "EVENTS"; + private static final String CHARACTER = "CHARACTER"; + private static final String SESSION = "SESSION"; + private static final String GLOBAL = "GLOBAL"; + private static final String VARIABLES = "VARIABLES"; + private static final String ERRORS = "ERRORS"; + private static final String STATUS = "STATUS"; + private static final String IGNORE = "IGNORE"; + private static final String RESET = "RESET"; + private static final String DESCRIBE = "DESCRIBE"; + private static final String WRITE = "WRITE"; + private static final String READ = "READ"; + private static final String LOCAL = "LOCAL"; + private static final String TABLES = "TABLES"; + private static final String TEMPORARY = "TEMPORARY"; + private static final String USER = "USER"; + private static final String SPATIAL = "SPATIAL"; + private static final String FULLTEXT = "FULLTEXT"; + private static final String DELAYED = "DELAYED"; + private static final String LOW_PRIORITY = "LOW_PRIORITY"; + + public MySqlStatementParser(String sql){ + super(new MySqlExprParser(sql)); + } + + public MySqlStatementParser(Lexer lexer){ + super(new MySqlExprParser(lexer)); + } + + public SQLCreateTableStatement parseCreateTable() { + MySqlCreateTableParser parser = new MySqlCreateTableParser(this.exprParser); + return parser.parseCrateTable(); + } + + public SQLSelectStatement parseSelect() { + MySqlSelectParser selectParser = new MySqlSelectParser(this.exprParser); + return new SQLSelectStatement(selectParser.select()); + } + + public SQLUpdateStatement parseUpdateStatement() { + MySqlUpdateStatement stmt = createUpdateStatement(); + + if (lexer.token() == Token.UPDATE) { + lexer.nextToken(); + + if (identifierEquals(LOW_PRIORITY)) { + lexer.nextToken(); + stmt.setLowPriority(true); + } + + if (identifierEquals(IGNORE)) { + lexer.nextToken(); + stmt.setIgnore(true); + } + + SQLTableSource tableSource = this.exprParser.createSelectParser().parseTableSource(); + stmt.setTableSource(tableSource); + } + + parseUpdateSet(stmt); + + if (lexer.token() == (Token.WHERE)) { + lexer.nextToken(); + stmt.setWhere(this.exprParser.expr()); + } + + stmt.setOrderBy(this.exprParser.parseOrderBy()); + + stmt.setLimit(parseLimit()); + + return stmt; + } + + protected MySqlUpdateStatement createUpdateStatement() { + return new MySqlUpdateStatement(); + } + + public MySqlDeleteStatement parseDeleteStatement() { + MySqlDeleteStatement deleteStatement = new MySqlDeleteStatement(); + + if (lexer.token() == Token.DELETE) { + lexer.nextToken(); + + if (lexer.token() == Token.COMMENT) { + lexer.nextToken(); + } + + if (identifierEquals(LOW_PRIORITY)) { + deleteStatement.setLowPriority(true); + lexer.nextToken(); + } + + if (identifierEquals("QUICK")) { + deleteStatement.setQuick(true); + lexer.nextToken(); + } + + if (identifierEquals(IGNORE)) { + deleteStatement.setIgnore(true); + lexer.nextToken(); + } + + if (lexer.token() == Token.IDENTIFIER) { + deleteStatement.setTableSource(createSQLSelectParser().parseTableSource()); + + if (lexer.token() == Token.FROM) { + lexer.nextToken(); + SQLTableSource tableSource = createSQLSelectParser().parseTableSource(); + deleteStatement.setFrom(tableSource); + } + } else { + if (lexer.token() == Token.FROM) { + lexer.nextToken(); + deleteStatement.setTableSource(createSQLSelectParser().parseTableSource()); + } + } + + if (identifierEquals("USING")) { + lexer.nextToken(); + + SQLTableSource tableSource = createSQLSelectParser().parseTableSource(); + deleteStatement.setUsing(tableSource); + } + } + + if (lexer.token() == (Token.WHERE)) { + lexer.nextToken(); + SQLExpr where = this.exprParser.expr(); + deleteStatement.setWhere(where); + } + + if (lexer.token() == (Token.ORDER)) { + SQLOrderBy orderBy = exprParser.parseOrderBy(); + deleteStatement.setOrderBy(orderBy); + } + + deleteStatement.setLimit(parseLimit()); + + return deleteStatement; + } + + public SQLStatement parseCreate() { + char markChar = lexer.current(); + int markBp = lexer.bp(); + + accept(Token.CREATE); + + boolean replace = false; + if (lexer.token() == Token.OR) { + lexer.nextToken(); + accept(Token.REPLACE); + replace = true; + } + + List hints = this.exprParser.parseHints(); + + if (lexer.token() == Token.TABLE || identifierEquals(TEMPORARY)) { + if (replace) { + lexer.reset(markBp, markChar, Token.CREATE); + } + MySqlCreateTableParser parser = new MySqlCreateTableParser(this.exprParser); + MySqlCreateTableStatement stmt = parser.parseCrateTable(false); + stmt.setHints(hints); + return stmt; + } + + if (lexer.token() == Token.DATABASE) { + if (replace) { + lexer.reset(markBp, markChar, Token.CREATE); + } + return parseCreateDatabase(); + } + + if (lexer.token() == Token.UNIQUE || lexer.token() == Token.INDEX || identifierEquals(FULLTEXT) + || identifierEquals(SPATIAL)) { + if (replace) { + lexer.reset(markBp, markChar, Token.CREATE); + } + return parseCreateIndex(); + } + + if (identifierEquals(USER)) { + if (replace) { + lexer.reset(markBp, markChar, Token.CREATE); + } + return parseCreateUser(); + } + + if (lexer.token() == Token.VIEW) { + if (replace) { + lexer.reset(markBp, markChar, Token.CREATE); + } + + return parseCreateView(); + } + + throw new ParserException("TODO " + lexer.token()); + } + + public SQLStatement parseCreateIndex() { + MySqlCreateIndexStatement stmt = new MySqlCreateIndexStatement(); + + if (lexer.token() == Token.UNIQUE) { + stmt.setType("UNIQUE"); + lexer.nextToken(); + } else if (identifierEquals(FULLTEXT)) { + stmt.setType(FULLTEXT); + lexer.nextToken(); + } else if (identifierEquals(SPATIAL)) { + stmt.setType(SPATIAL); + lexer.nextToken(); + } + + accept(Token.INDEX); + + stmt.setName(this.exprParser.name()); + + parseCreateIndexUsing(stmt); + + accept(Token.ON); + + stmt.setTable(this.exprParser.name()); + + accept(Token.LPAREN); + + for (;;) { + SQLSelectOrderByItem item = this.exprParser.parseSelectOrderByItem(); + stmt.getItems().add(item); + if (lexer.token() == Token.COMMA) { + lexer.nextToken(); + continue; + } + break; + } + accept(Token.RPAREN); + + parseCreateIndexUsing(stmt); + + return stmt; + } + + private void parseCreateIndexUsing(MySqlCreateIndexStatement stmt) { + if (identifierEquals("USING")) { + lexer.nextToken(); + + if (identifierEquals("BTREE")) { + stmt.setUsing("BTREE"); + lexer.nextToken(); + } else if (identifierEquals("HASH")) { + stmt.setUsing("HASH"); + lexer.nextToken(); + } else { + throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); + } + } + } + + public SQLStatement parseCreateUser() { + if (lexer.token() == Token.CREATE) { + lexer.nextToken(); + } + + acceptIdentifier(USER); + + MySqlCreateUserStatement stmt = new MySqlCreateUserStatement(); + + for (;;) { + MySqlCreateUserStatement.UserSpecification userSpec = new MySqlCreateUserStatement.UserSpecification(); + + SQLExpr expr = exprParser.primary(); + userSpec.setUser(expr); + + if (lexer.token() == Token.IDENTIFIED) { + lexer.nextToken(); + if (lexer.token() == Token.BY) { + lexer.nextToken(); + + if (identifierEquals("PASSWORD")) { + lexer.nextToken(); + } + + SQLCharExpr password = (SQLCharExpr) this.exprParser.expr(); + userSpec.setPassword(password); + } else if (lexer.token() == Token.WITH) { + lexer.nextToken(); + + SQLCharExpr text = (SQLCharExpr) this.exprParser.expr(); + userSpec.setAuthPlugin(text); + } + } + + stmt.getUsers().add(userSpec); + + if (lexer.token() == Token.COMMA) { + lexer.nextToken(); + continue; + } + + break; + } + + return stmt; + } + + public SQLStatement parseKill() { + accept(Token.KILL); + + MySqlKillStatement stmt = new MySqlKillStatement(); + + if (identifierEquals("CONNECTION")) { + stmt.setType(MySqlKillStatement.Type.CONNECTION); + lexer.nextToken(); + } else if (identifierEquals("QUERY")) { + stmt.setType(MySqlKillStatement.Type.QUERY); + lexer.nextToken(); + } else { + throw new ParserException("not support kill type " + lexer.token()); + } + + SQLExpr threadId = this.exprParser.expr(); + stmt.setThreadId(threadId); + + return stmt; + } + + public SQLStatement parseBinlog() { + acceptIdentifier("binlog"); + + MySqlBinlogStatement stmt = new MySqlBinlogStatement(); + + SQLExpr expr = this.exprParser.expr(); + stmt.setExpr(expr); + + return stmt; + } + + public SQLStatement parseReset() { + acceptIdentifier(RESET); + + MySqlResetStatement stmt = new MySqlResetStatement(); + + for (;;) { + if (lexer.token() == Token.IDENTIFIER) { + if (identifierEquals("QUERY")) { + lexer.nextToken(); + acceptIdentifier("CACHE"); + stmt.getOptions().add("QUERY CACHE"); + } else { + stmt.getOptions().add(lexer.stringVal()); + lexer.nextToken(); + } + + if (lexer.token() == Token.COMMA) { + lexer.nextToken(); + continue; + } + } + break; + } + + return stmt; + } + + public boolean parseStatementListDialect(List statementList) { + if (lexer.token() == Token.KILL) { + SQLStatement stmt = parseKill(); + statementList.add(stmt); + return true; + } + + if (identifierEquals("PREPARE")) { + MySqlPrepareStatement stmt = parsePrepare(); + statementList.add(stmt); + return true; + } + + if (identifierEquals("EXECUTE")) { + MySqlExecuteStatement stmt = parseExecute(); + statementList.add(stmt); + return true; + } + + if (identifierEquals("LOAD")) { + SQLStatement stmt = parseLoad(); + statementList.add(stmt); + return true; + } + + if (lexer.token() == Token.REPLACE) { + MySqlReplaceStatement stmt = parseReplicate(); + statementList.add(stmt); + return true; + } + + if (identifierEquals("START")) { + MySqlStartTransactionStatement stmt = parseStart(); + statementList.add(stmt); + return true; + } + + if (lexer.token() == Token.SHOW) { + SQLStatement stmt = parseShow(); + statementList.add(stmt); + return true; + } + + if (identifierEquals(BINLOG)) { + SQLStatement stmt = parseBinlog(); + statementList.add(stmt); + return true; + } + + if (identifierEquals(RESET)) { + SQLStatement stmt = parseReset(); + statementList.add(stmt); + return true; + } + + if (identifierEquals("HELP")) { + lexer.nextToken(); + MySqlHelpStatement stmt = new MySqlHelpStatement(); + stmt.setContent(this.exprParser.primary()); + statementList.add(stmt); + return true; + } + + if (lexer.token() == Token.DESC || identifierEquals(DESCRIBE)) { + SQLStatement stmt = parseDescribe(); + statementList.add(stmt); + return true; + } + + if (lexer.token() == Token.LOCK) { + lexer.nextToken(); + acceptIdentifier(TABLES); + + MySqlLockTableStatement stmt = new MySqlLockTableStatement(); + stmt.setTableSource(this.exprParser.name()); + + if (identifierEquals(READ)) { + lexer.nextToken(); + if (identifierEquals(LOCAL)) { + lexer.nextToken(); + stmt.setLockType(LockType.READ_LOCAL); + } else { + stmt.setLockType(LockType.READ); + } + } else if (identifierEquals(WRITE)) { + stmt.setLockType(LockType.WRITE); + } else if (identifierEquals(LOW_PRIORITY)) { + lexer.nextToken(); + acceptIdentifier(WRITE); + stmt.setLockType(LockType.LOW_PRIORITY_WRITE); + } + + statementList.add(stmt); + return true; + } + + if (identifierEquals("UNLOCK")) { + lexer.nextToken(); + acceptIdentifier(TABLES); + statementList.add(new MySqlUnlockTablesStatement()); + return true; + } + + return false; + } + + public MySqlDescribeStatement parseDescribe() { + if (lexer.token() == Token.DESC || identifierEquals(DESCRIBE)) { + lexer.nextToken(); + } else { + throw new ParserException("expect DESC, actual " + lexer.token()); + } + + MySqlDescribeStatement stmt = new MySqlDescribeStatement(); + stmt.setObject(this.exprParser.name()); + + return stmt; + } + + public SQLStatement parseShow() { + accept(Token.SHOW); + + if (lexer.token() == Token.COMMENT) { + lexer.nextToken(); + } + + boolean full = false; + if (lexer.token() == Token.FULL) { + lexer.nextToken(); + full = true; + } + + if (identifierEquals("PROCESSLIST")) { + lexer.nextToken(); + MySqlShowProcessListStatement stmt = new MySqlShowProcessListStatement(); + stmt.setFull(full); + return stmt; + } + + if (identifierEquals("COLUMNS") || identifierEquals("FIELDS")) { + lexer.nextToken(); + + MySqlShowColumnsStatement stmt = parseShowColumns(); + stmt.setFull(full); + + return stmt; + } + + if (identifierEquals("COLUMNS")) { + lexer.nextToken(); + + MySqlShowColumnsStatement stmt = parseShowColumns(); + + return stmt; + } + + if (identifierEquals(TABLES)) { + lexer.nextToken(); + + MySqlShowTablesStatement stmt = parseShowTabless(); + stmt.setFull(full); + + return stmt; + } + + if (identifierEquals("DATABASES")) { + lexer.nextToken(); + + MySqlShowDatabasesStatement stmt = parseShowDatabases(); + + return stmt; + } + + if (identifierEquals("WARNINGS")) { + lexer.nextToken(); + + MySqlShowWarningsStatement stmt = parseShowWarnings(); + + return stmt; + } + + if (identifierEquals("COUNT")) { + lexer.nextToken(); + accept(Token.LPAREN); + accept(Token.STAR); + accept(Token.RPAREN); + + if (identifierEquals(ERRORS)) { + lexer.nextToken(); + + MySqlShowErrorsStatement stmt = new MySqlShowErrorsStatement(); + stmt.setCount(true); + + return stmt; + } else { + acceptIdentifier("WARNINGS"); + + MySqlShowWarningsStatement stmt = new MySqlShowWarningsStatement(); + stmt.setCount(true); + + return stmt; + } + } + + if (identifierEquals(ERRORS)) { + lexer.nextToken(); + + MySqlShowErrorsStatement stmt = new MySqlShowErrorsStatement(); + stmt.setLimit(parseLimit()); + + return stmt; + } + + if (identifierEquals(STATUS)) { + lexer.nextToken(); + + MySqlShowStatusStatement stmt = parseShowStatus(); + + return stmt; + } + + if (identifierEquals(VARIABLES)) { + lexer.nextToken(); + + MySqlShowVariantsStatement stmt = parseShowVariants(); + + return stmt; + } + + if (identifierEquals(GLOBAL)) { + lexer.nextToken(); + + if (identifierEquals(STATUS)) { + lexer.nextToken(); + MySqlShowStatusStatement stmt = parseShowStatus(); + stmt.setGlobal(true); + return stmt; + } + + if (identifierEquals(VARIABLES)) { + lexer.nextToken(); + MySqlShowVariantsStatement stmt = parseShowVariants(); + stmt.setGlobal(true); + return stmt; + } + } + + if (identifierEquals(SESSION)) { + lexer.nextToken(); + + if (identifierEquals(STATUS)) { + lexer.nextToken(); + MySqlShowStatusStatement stmt = parseShowStatus(); + stmt.setSession(true); + return stmt; + } + + if (identifierEquals(VARIABLES)) { + lexer.nextToken(); + MySqlShowVariantsStatement stmt = parseShowVariants(); + stmt.setSession(true); + return stmt; + } + } + + if (identifierEquals("COBAR_STATUS")) { + lexer.nextToken(); + return new CobarShowStatus(); + } + + if (identifierEquals("AUTHORS")) { + lexer.nextToken(); + return new MySqlShowAuthorsStatement(); + } + + if (lexer.token() == Token.BINARY) { + lexer.nextToken(); + acceptIdentifier("LOGS"); + return new MySqlShowBinaryLogsStatement(); + } + + if (identifierEquals("MASTER")) { + lexer.nextToken(); + if (identifierEquals("LOGS")) { + lexer.nextToken(); + return new MySqlShowMasterLogsStatement(); + } + acceptIdentifier(STATUS); + return new MySqlShowMasterStatusStatement(); + } + + if (identifierEquals(CHARACTER)) { + lexer.nextToken(); + accept(Token.SET); + MySqlShowCharacterSetStatement stmt = new MySqlShowCharacterSetStatement(); + + if (lexer.token() == Token.LIKE) { + lexer.nextToken(); + stmt.setPattern(this.exprParser.expr()); + } + + if (lexer.token() == Token.WHERE) { + lexer.nextToken(); + stmt.setWhere(this.exprParser.expr()); + } + + return stmt; + } + + if (identifierEquals("COLLATION")) { + lexer.nextToken(); + MySqlShowCollationStatement stmt = new MySqlShowCollationStatement(); + + if (lexer.token() == Token.LIKE) { + lexer.nextToken(); + stmt.setPattern(this.exprParser.expr()); + } + + if (lexer.token() == Token.WHERE) { + lexer.nextToken(); + stmt.setWhere(this.exprParser.expr()); + } + + return stmt; + } + + if (identifierEquals(BINLOG)) { + lexer.nextToken(); + acceptIdentifier(EVENTS); + MySqlShowBinLogEventsStatement stmt = new MySqlShowBinLogEventsStatement(); + + if (lexer.token() == Token.IN) { + lexer.nextToken(); + stmt.setIn(this.exprParser.expr()); + } + + if (lexer.token() == Token.FROM) { + lexer.nextToken(); + stmt.setFrom(this.exprParser.expr()); + } + + stmt.setLimit(parseLimit()); + + return stmt; + } + + if (identifierEquals("CONTRIBUTORS")) { + lexer.nextToken(); + return new MySqlShowContributorsStatement(); + } + + if (lexer.token() == Token.CREATE) { + lexer.nextToken(); + + if (lexer.token() == Token.DATABASE) { + lexer.nextToken(); + + MySqlShowCreateDatabaseStatement stmt = new MySqlShowCreateDatabaseStatement(); + stmt.setDatabase(this.exprParser.name()); + return stmt; + } + + if (identifierEquals("EVENT")) { + lexer.nextToken(); + + MySqlShowCreateEventStatement stmt = new MySqlShowCreateEventStatement(); + stmt.setEventName(this.exprParser.name()); + return stmt; + } + + if (identifierEquals("FUNCTION")) { + lexer.nextToken(); + + MySqlShowCreateFunctionStatement stmt = new MySqlShowCreateFunctionStatement(); + stmt.setName(this.exprParser.name()); + return stmt; + } + + if (identifierEquals("PROCEDURE")) { + lexer.nextToken(); + + MySqlShowCreateProcedureStatement stmt = new MySqlShowCreateProcedureStatement(); + stmt.setName(this.exprParser.name()); + return stmt; + } + + if (lexer.token() == Token.TABLE) { + lexer.nextToken(); + + MySqlShowCreateTableStatement stmt = new MySqlShowCreateTableStatement(); + stmt.setName(this.exprParser.name()); + return stmt; + } + + if (lexer.token() == Token.VIEW) { + lexer.nextToken(); + + MySqlShowCreateViewStatement stmt = new MySqlShowCreateViewStatement(); + stmt.setName(this.exprParser.name()); + return stmt; + } + + if (identifierEquals("TRIGGER")) { + lexer.nextToken(); + + MySqlShowCreateTriggerStatement stmt = new MySqlShowCreateTriggerStatement(); + stmt.setName(this.exprParser.name()); + return stmt; + } + + throw new ParserException("TODO " + lexer.stringVal()); + } + + if (identifierEquals(ENGINE)) { + lexer.nextToken(); + MySqlShowEngineStatement stmt = new MySqlShowEngineStatement(); + stmt.setName(this.exprParser.name()); + stmt.setOption(MySqlShowEngineStatement.Option.valueOf(lexer.stringVal().toUpperCase())); + lexer.nextToken(); + return stmt; + } + + if (identifierEquals("STORAGE")) { + lexer.nextToken(); + acceptIdentifier(ENGINES); + MySqlShowEnginesStatement stmt = new MySqlShowEnginesStatement(); + stmt.setStorage(true); + return stmt; + } + + if (identifierEquals(ENGINES)) { + lexer.nextToken(); + MySqlShowEnginesStatement stmt = new MySqlShowEnginesStatement(); + return stmt; + } + + if (identifierEquals(EVENTS)) { + lexer.nextToken(); + MySqlShowEventsStatement stmt = new MySqlShowEventsStatement(); + + if (lexer.token() == Token.FROM || lexer.token() == Token.IN) { + lexer.nextToken(); + stmt.setSchema(this.exprParser.name()); + } + + if (lexer.token() == Token.LIKE) { + lexer.nextToken(); + stmt.setLike(this.exprParser.expr()); + } + + if (lexer.token() == Token.WHERE) { + lexer.nextToken(); + stmt.setWhere(this.exprParser.expr()); + } + return stmt; + } + + if (identifierEquals("FUNCTION")) { + lexer.nextToken(); + + if (identifierEquals("CODE")) { + lexer.nextToken(); + MySqlShowFunctionCodeStatement stmt = new MySqlShowFunctionCodeStatement(); + stmt.setName(this.exprParser.name()); + return stmt; + } + + acceptIdentifier(STATUS); + MySqlShowFunctionStatusStatement stmt = new MySqlShowFunctionStatusStatement(); + + if (lexer.token() == Token.LIKE) { + lexer.nextToken(); + stmt.setLike(this.exprParser.expr()); + } + + if (lexer.token() == Token.WHERE) { + lexer.nextToken(); + stmt.setWhere(this.exprParser.expr()); + } + return stmt; + } + + // MySqlShowFunctionStatusStatement + + if (identifierEquals(ENGINE)) { + lexer.nextToken(); + MySqlShowEngineStatement stmt = new MySqlShowEngineStatement(); + stmt.setName(this.exprParser.name()); + stmt.setOption(MySqlShowEngineStatement.Option.valueOf(lexer.stringVal().toUpperCase())); + lexer.nextToken(); + return stmt; + } + + if (identifierEquals("STORAGE")) { + lexer.nextToken(); + acceptIdentifier(ENGINES); + MySqlShowEnginesStatement stmt = new MySqlShowEnginesStatement(); + stmt.setStorage(true); + return stmt; + } + + if (identifierEquals(ENGINES)) { + lexer.nextToken(); + MySqlShowEnginesStatement stmt = new MySqlShowEnginesStatement(); + return stmt; + } + + if (identifierEquals("GRANTS")) { + lexer.nextToken(); + MySqlShowGrantsStatement stmt = new MySqlShowGrantsStatement(); + + if (lexer.token() == Token.FOR) { + lexer.nextToken(); + stmt.setUser(this.exprParser.expr()); + } + + return stmt; + } + + if (lexer.token() == Token.INDEX || identifierEquals("INDEXES")) { + lexer.nextToken(); + MySqlShowIndexesStatement stmt = new MySqlShowIndexesStatement(); + + if (lexer.token() == Token.FROM || lexer.token() == Token.IN) { + lexer.nextToken(); + SQLName table = exprParser.name(); + stmt.setTable(table); + + if (lexer.token() == Token.FROM || lexer.token() == Token.IN) { + lexer.nextToken(); + SQLName database = exprParser.name(); + stmt.setDatabase(database); + } + } + + return stmt; + } + + if (identifierEquals("KEYS")) { + lexer.nextToken(); + MySqlShowKeysStatement stmt = new MySqlShowKeysStatement(); + + if (lexer.token() == Token.FROM || lexer.token() == Token.IN) { + lexer.nextToken(); + SQLName table = exprParser.name(); + stmt.setTable(table); + + if (lexer.token() == Token.FROM || lexer.token() == Token.IN) { + lexer.nextToken(); + SQLName database = exprParser.name(); + stmt.setDatabase(database); + } + } + + return stmt; + } + + if (identifierEquals("OPEN")) { + lexer.nextToken(); + acceptIdentifier(TABLES); + MySqlShowOpenTablesStatement stmt = new MySqlShowOpenTablesStatement(); + + if (lexer.token() == Token.FROM || lexer.token() == Token.IN) { + lexer.nextToken(); + stmt.setDatabase(this.exprParser.name()); + } + + if (lexer.token() == Token.LIKE) { + lexer.nextToken(); + stmt.setLike(this.exprParser.expr()); + } + + if (lexer.token() == Token.WHERE) { + lexer.nextToken(); + stmt.setWhere(this.exprParser.expr()); + } + return stmt; + } + + if (identifierEquals("PLUGINS")) { + lexer.nextToken(); + MySqlShowPluginsStatement stmt = new MySqlShowPluginsStatement(); + return stmt; + } + + if (identifierEquals("PRIVILEGES")) { + lexer.nextToken(); + MySqlShowPrivilegesStatement stmt = new MySqlShowPrivilegesStatement(); + return stmt; + } + + if (identifierEquals("PROCEDURE")) { + lexer.nextToken(); + + if (identifierEquals("CODE")) { + lexer.nextToken(); + MySqlShowProcedureCodeStatement stmt = new MySqlShowProcedureCodeStatement(); + stmt.setName(this.exprParser.name()); + return stmt; + } + + acceptIdentifier(STATUS); + MySqlShowProcedureStatusStatement stmt = new MySqlShowProcedureStatusStatement(); + + if (lexer.token() == Token.LIKE) { + lexer.nextToken(); + stmt.setLike(this.exprParser.expr()); + } + + if (lexer.token() == Token.WHERE) { + lexer.nextToken(); + stmt.setWhere(this.exprParser.expr()); + } + return stmt; + } + + if (identifierEquals("PROCESSLIST")) { + lexer.nextToken(); + MySqlShowProcessListStatement stmt = new MySqlShowProcessListStatement(); + return stmt; + } + + if (identifierEquals("PROFILES")) { + lexer.nextToken(); + MySqlShowProfilesStatement stmt = new MySqlShowProfilesStatement(); + return stmt; + } + + if (identifierEquals("PROFILE")) { + lexer.nextToken(); + MySqlShowProfileStatement stmt = new MySqlShowProfileStatement(); + + for (;;) { + if (lexer.token() == Token.ALL) { + stmt.getTypes().add(MySqlShowProfileStatement.Type.ALL); + lexer.nextToken(); + } else if (identifierEquals("BLOCK")) { + lexer.nextToken(); + acceptIdentifier("IO"); + stmt.getTypes().add(MySqlShowProfileStatement.Type.BLOCK_IO); + } else if (identifierEquals("CONTEXT")) { + lexer.nextToken(); + acceptIdentifier("SWITCHES"); + stmt.getTypes().add(MySqlShowProfileStatement.Type.CONTEXT_SWITCHES); + } else if (identifierEquals("CPU")) { + lexer.nextToken(); + stmt.getTypes().add(MySqlShowProfileStatement.Type.CPU); + } else if (identifierEquals("IPC")) { + lexer.nextToken(); + stmt.getTypes().add(MySqlShowProfileStatement.Type.IPC); + } else if (identifierEquals("MEMORY")) { + lexer.nextToken(); + stmt.getTypes().add(MySqlShowProfileStatement.Type.MEMORY); + } else if (identifierEquals("PAGE")) { + lexer.nextToken(); + acceptIdentifier("FAULTS"); + stmt.getTypes().add(MySqlShowProfileStatement.Type.PAGE_FAULTS); + } else if (identifierEquals("SOURCE")) { + lexer.nextToken(); + stmt.getTypes().add(MySqlShowProfileStatement.Type.SOURCE); + } else if (identifierEquals("SWAPS")) { + lexer.nextToken(); + stmt.getTypes().add(MySqlShowProfileStatement.Type.SWAPS); + } else { + break; + } + + if (lexer.token() == Token.COMMA) { + lexer.nextToken(); + continue; + } + break; + } + + if (lexer.token() == Token.FOR) { + lexer.nextToken(); + acceptIdentifier("QUERY"); + stmt.setForQuery(this.exprParser.primary()); + } + + stmt.setLimit(this.parseLimit()); + + return stmt; + } + + if (identifierEquals("RELAYLOG")) { + lexer.nextToken(); + acceptIdentifier(EVENTS); + MySqlShowRelayLogEventsStatement stmt = new MySqlShowRelayLogEventsStatement(); + + if (lexer.token() == Token.IN) { + lexer.nextToken(); + stmt.setLogName(this.exprParser.primary()); + } + + if (lexer.token() == Token.FROM) { + lexer.nextToken(); + stmt.setFrom(this.exprParser.primary()); + } + + stmt.setLimit(this.parseLimit()); + + return stmt; + } + + if (identifierEquals("RELAYLOG")) { + lexer.nextToken(); + acceptIdentifier(EVENTS); + MySqlShowRelayLogEventsStatement stmt = new MySqlShowRelayLogEventsStatement(); + + if (lexer.token() == Token.IN) { + lexer.nextToken(); + stmt.setLogName(this.exprParser.primary()); + } + + if (lexer.token() == Token.FROM) { + lexer.nextToken(); + stmt.setFrom(this.exprParser.primary()); + } + + stmt.setLimit(this.parseLimit()); + + return stmt; + } + + if (identifierEquals("SLAVE")) { + lexer.nextToken(); + if (identifierEquals(STATUS)) { + lexer.nextToken(); + return new MySqlShowSlaveStatusStatement(); + } else { + acceptIdentifier("HOSTS"); + MySqlShowSlaveHostsStatement stmt = new MySqlShowSlaveHostsStatement(); + return stmt; + } + } + + if (lexer.token() == Token.TABLE) { + lexer.nextToken(); + acceptIdentifier(STATUS); + MySqlShowTableStatusStatement stmt = new MySqlShowTableStatusStatement(); + if (lexer.token() == Token.FROM || lexer.token() == Token.IN) { + lexer.nextToken(); + stmt.setDatabase(this.exprParser.name()); + } + + if (lexer.token() == Token.LIKE) { + lexer.nextToken(); + stmt.setLike(this.exprParser.expr()); + } + + if (lexer.token() == Token.WHERE) { + lexer.nextToken(); + stmt.setWhere(this.exprParser.expr()); + } + + return stmt; + } + + if (identifierEquals("TRIGGERS")) { + lexer.nextToken(); + MySqlShowTriggersStatement stmt = new MySqlShowTriggersStatement(); + + if (lexer.token() == Token.FROM) { + lexer.nextToken(); + SQLName database = exprParser.name(); + stmt.setDatabase(database); + } + + if (lexer.token() == Token.LIKE) { + lexer.nextToken(); + SQLExpr like = exprParser.expr(); + stmt.setLike(like); + } + + if (lexer.token() == Token.WHERE) { + lexer.nextToken(); + SQLExpr where = exprParser.expr(); + stmt.setWhere(where); + } + + return stmt; + } + + // MySqlShowSlaveHostsStatement + throw new ParserException("TODO " + lexer.stringVal()); + } + + private MySqlShowStatusStatement parseShowStatus() { + MySqlShowStatusStatement stmt = new MySqlShowStatusStatement(); + + if (lexer.token() == Token.LIKE) { + lexer.nextToken(); + SQLExpr like = exprParser.expr(); + stmt.setLike(like); + } + + if (lexer.token() == Token.WHERE) { + lexer.nextToken(); + SQLExpr where = exprParser.expr(); + stmt.setWhere(where); + } + + return stmt; + } + + private MySqlShowVariantsStatement parseShowVariants() { + MySqlShowVariantsStatement stmt = new MySqlShowVariantsStatement(); + + if (lexer.token() == Token.LIKE) { + lexer.nextToken(); + SQLExpr like = exprParser.expr(); + stmt.setLike(like); + } + + if (lexer.token() == Token.WHERE) { + lexer.nextToken(); + SQLExpr where = exprParser.expr(); + stmt.setWhere(where); + } + + return stmt; + } + + private MySqlShowWarningsStatement parseShowWarnings() { + MySqlShowWarningsStatement stmt = new MySqlShowWarningsStatement(); + + stmt.setLimit(parseLimit()); + + return stmt; + } + + private MySqlShowDatabasesStatement parseShowDatabases() { + MySqlShowDatabasesStatement stmt = new MySqlShowDatabasesStatement(); + + if (lexer.token() == Token.LIKE) { + lexer.nextToken(); + SQLExpr like = exprParser.expr(); + stmt.setLike(like); + } + + if (lexer.token() == Token.WHERE) { + lexer.nextToken(); + SQLExpr where = exprParser.expr(); + stmt.setWhere(where); + } + + return stmt; + } + + private MySqlShowTablesStatement parseShowTabless() { + MySqlShowTablesStatement stmt = new MySqlShowTablesStatement(); + + if (lexer.token() == Token.FROM) { + lexer.nextToken(); + SQLName database = exprParser.name(); + stmt.setDatabase(database); + } + + if (lexer.token() == Token.LIKE) { + lexer.nextToken(); + SQLExpr like = exprParser.expr(); + stmt.setLike(like); + } + + if (lexer.token() == Token.WHERE) { + lexer.nextToken(); + SQLExpr where = exprParser.expr(); + stmt.setWhere(where); + } + + return stmt; + } + + private MySqlShowColumnsStatement parseShowColumns() { + MySqlShowColumnsStatement stmt = new MySqlShowColumnsStatement(); + + if (lexer.token() == Token.FROM) { + lexer.nextToken(); + SQLName table = exprParser.name(); + stmt.setTable(table); + + if (lexer.token() == Token.FROM) { + lexer.nextToken(); + SQLName database = exprParser.name(); + stmt.setDatabase(database); + } + } + + if (lexer.token() == Token.LIKE) { + lexer.nextToken(); + SQLExpr like = exprParser.expr(); + stmt.setLike(like); + } + + if (lexer.token() == Token.WHERE) { + lexer.nextToken(); + SQLExpr where = exprParser.expr(); + stmt.setWhere(where); + } + + return stmt; + } + + public MySqlStartTransactionStatement parseStart() { + acceptIdentifier("START"); + acceptIdentifier("TRANSACTION"); + + MySqlStartTransactionStatement stmt = new MySqlStartTransactionStatement(); + + if (identifierEquals("WITH")) { + lexer.nextToken(); + acceptIdentifier("CONSISTENT"); + acceptIdentifier("SNAPSHOT"); + stmt.setConsistentSnapshot(true); + } + + if (identifierEquals("BEGIN")) { + lexer.nextToken(); + stmt.setBegin(true); + if (identifierEquals("WORK")) { + lexer.nextToken(); + stmt.setWork(true); + } + } + + return stmt; + } + + @Override + public MySqlRollbackStatement parseRollback() { + acceptIdentifier("ROLLBACK"); + + MySqlRollbackStatement stmt = new MySqlRollbackStatement(); + + if (identifierEquals("WORK")) { + lexer.nextToken(); + } + + if (lexer.token() == Token.AND) { + lexer.nextToken(); + if (lexer.token() == Token.NOT) { + lexer.nextToken(); + acceptIdentifier(CHAIN); + stmt.setChain(Boolean.FALSE); + } else { + acceptIdentifier(CHAIN); + stmt.setChain(Boolean.TRUE); + } + } + + if (lexer.token() == Token.TO) { + lexer.nextToken(); + + if (identifierEquals("SAVEPOINT")) { + lexer.nextToken(); + } + + stmt.setTo(this.exprParser.name()); + } + + return stmt; + } + + public MySqlCommitStatement parseCommit() { + acceptIdentifier("COMMIT"); + + MySqlCommitStatement stmt = new MySqlCommitStatement(); + + if (identifierEquals("WORK")) { + lexer.nextToken(); + stmt.setWork(true); + } + + if (lexer.token() == Token.AND) { + lexer.nextToken(); + if (lexer.token() == Token.NOT) { + lexer.nextToken(); + acceptIdentifier(CHAIN); + stmt.setChain(Boolean.FALSE); + } else { + acceptIdentifier(CHAIN); + stmt.setChain(Boolean.TRUE); + } + } + + return stmt; + } + + public MySqlReplaceStatement parseReplicate() { + MySqlReplaceStatement stmt = new MySqlReplaceStatement(); + + accept(Token.REPLACE); + + if (lexer.token() == Token.COMMENT) { + lexer.nextToken(); + } + + if (identifierEquals(LOW_PRIORITY)) { + stmt.setLowPriority(true); + lexer.nextToken(); + } + + if (identifierEquals(DELAYED)) { + stmt.setDelayed(true); + lexer.nextToken(); + } + + if (lexer.token() == Token.INTO) { + lexer.nextToken(); + } + + SQLName tableName = exprParser.name(); + stmt.setTableName(tableName); + + if (lexer.token() == Token.LPAREN) { + lexer.nextToken(); + if (lexer.token() == Token.SELECT) { + SQLQueryExpr queryExpr = (SQLQueryExpr) this.exprParser.expr(); + stmt.setQuery(queryExpr); + } else { + this.exprParser.exprList(stmt.getColumns()); + } + accept(Token.RPAREN); + } + + if (lexer.token() == Token.VALUES || identifierEquals("VALUE")) { + lexer.nextToken(); + + parseValueClause(stmt.getValuesList(), 0); + } else if (lexer.token() == Token.SELECT) { + SQLQueryExpr queryExpr = (SQLQueryExpr) this.exprParser.expr(); + stmt.setQuery(queryExpr); + } else if (lexer.token() == Token.SET) { + lexer.nextToken(); + + SQLInsertStatement.ValuesClause values = new SQLInsertStatement.ValuesClause(); + stmt.getValuesList().add(values); + for (;;) { + stmt.getColumns().add(this.exprParser.name()); + if (lexer.token() == Token.COLONEQ) { + lexer.nextToken(); + } else { + accept(Token.EQ); + } + values.getValues().add(this.exprParser.expr()); + + if (lexer.token() == (Token.COMMA)) { + lexer.nextToken(); + continue; + } + + break; + } + } else if (lexer.token() == Token.LPAREN) { + lexer.nextToken(); + SQLQueryExpr queryExpr = (SQLQueryExpr) this.exprParser.expr(); + stmt.setQuery(queryExpr); + accept(Token.RPAREN); + } + + return stmt; + } + + protected SQLStatement parseLoad() { + acceptIdentifier("LOAD"); + + if (identifierEquals("DATA")) { + SQLStatement stmt = parseLoadDataInFile(); + return stmt; + } + + if (identifierEquals("XML")) { + SQLStatement stmt = parseLoadXml(); + return stmt; + } + + throw new ParserException("TODO"); + } + + protected MySqlLoadXmlStatement parseLoadXml() { + acceptIdentifier("XML"); + + MySqlLoadXmlStatement stmt = new MySqlLoadXmlStatement(); + + if (identifierEquals(LOW_PRIORITY)) { + stmt.setLowPriority(true); + lexer.nextToken(); + } + + if (identifierEquals("CONCURRENT")) { + stmt.setConcurrent(true); + lexer.nextToken(); + } + + if (identifierEquals(LOCAL)) { + stmt.setLocal(true); + lexer.nextToken(); + } + + acceptIdentifier("INFILE"); + + SQLLiteralExpr fileName = (SQLLiteralExpr) exprParser.expr(); + stmt.setFileName(fileName); + + if (lexer.token() == Token.REPLACE) { + stmt.setReplicate(true); + lexer.nextToken(); + } + + if (identifierEquals(IGNORE)) { + stmt.setIgnore(true); + lexer.nextToken(); + } + + accept(Token.INTO); + accept(Token.TABLE); + + SQLName tableName = exprParser.name(); + stmt.setTableName(tableName); + + if (identifierEquals(CHARACTER)) { + lexer.nextToken(); + accept(Token.SET); + + if (lexer.token() != Token.LITERAL_CHARS) { + throw new ParserException("syntax error, illegal charset"); + } + + String charset = lexer.stringVal(); + lexer.nextToken(); + stmt.setCharset(charset); + } + + if (identifierEquals("ROWS")) { + lexer.nextToken(); + accept(Token.IDENTIFIED); + accept(Token.BY); + SQLExpr rowsIdentifiedBy = exprParser.expr(); + stmt.setRowsIdentifiedBy(rowsIdentifiedBy); + } + + if (identifierEquals(IGNORE)) { + throw new ParserException("TODO"); + } + + if (lexer.token() == Token.SET) { + throw new ParserException("TODO"); + } + + return stmt; + } + + protected MySqlLoadDataInFileStatement parseLoadDataInFile() { + acceptIdentifier("DATA"); + + MySqlLoadDataInFileStatement stmt = new MySqlLoadDataInFileStatement(); + + if (identifierEquals(LOW_PRIORITY)) { + stmt.setLowPriority(true); + lexer.nextToken(); + } + + if (identifierEquals("CONCURRENT")) { + stmt.setConcurrent(true); + lexer.nextToken(); + } + + if (identifierEquals(LOCAL)) { + stmt.setLocal(true); + lexer.nextToken(); + } + + acceptIdentifier("INFILE"); + + SQLLiteralExpr fileName = (SQLLiteralExpr) exprParser.expr(); + stmt.setFileName(fileName); + + if (lexer.token() == Token.REPLACE) { + stmt.setReplicate(true); + lexer.nextToken(); + } + + if (identifierEquals(IGNORE)) { + stmt.setIgnore(true); + lexer.nextToken(); + } + + accept(Token.INTO); + accept(Token.TABLE); + + SQLName tableName = exprParser.name(); + stmt.setTableName(tableName); + + if (identifierEquals(CHARACTER)) { + lexer.nextToken(); + accept(Token.SET); + + if (lexer.token() != Token.LITERAL_CHARS) { + throw new ParserException("syntax error, illegal charset"); + } + + String charset = lexer.stringVal(); + lexer.nextToken(); + stmt.setCharset(charset); + } + + if (identifierEquals("FIELDS") || identifierEquals("COLUMNS")) { + throw new ParserException("TODO"); + } + + if (identifierEquals("LINES")) { + throw new ParserException("TODO"); + } + + if (identifierEquals(IGNORE)) { + throw new ParserException("TODO"); + } + + if (lexer.token() == Token.SET) { + throw new ParserException("TODO"); + } + + return stmt; + } + + public MySqlPrepareStatement parsePrepare() { + acceptIdentifier("PREPARE"); + + SQLName name = exprParser.name(); + accept(Token.FROM); + SQLExpr from = exprParser.expr(); + + return new MySqlPrepareStatement(name, from); + } + + public MySqlExecuteStatement parseExecute() { + acceptIdentifier("EXECUTE"); + + MySqlExecuteStatement stmt = new MySqlExecuteStatement(); + + SQLName statementName = exprParser.name(); + stmt.setStatementName(statementName); + + if (identifierEquals("USING")) { + lexer.nextToken(); + exprParser.exprList(stmt.getParameters()); + } + + return stmt; + } + + public SQLInsertStatement parseInsert() { + MySqlInsertStatement insertStatement = new MySqlInsertStatement(); + + if (lexer.token() == Token.INSERT) { + lexer.nextToken(); + + if (identifierEquals(LOW_PRIORITY)) { + insertStatement.setLowPriority(true); + lexer.nextToken(); + } + + if (identifierEquals(DELAYED)) { + insertStatement.setDelayed(true); + lexer.nextToken(); + } + + if (identifierEquals("HIGH_PRIORITY")) { + insertStatement.setHighPriority(true); + lexer.nextToken(); + } + + if (identifierEquals(IGNORE)) { + insertStatement.setIgnore(true); + lexer.nextToken(); + } + + if (lexer.token() == Token.INTO) { + lexer.nextToken(); + } + + SQLName tableName = this.exprParser.name(); + insertStatement.setTableName(tableName); + + if (lexer.token() == Token.IDENTIFIER && !identifierEquals("VALUE")) { + insertStatement.setAlias(lexer.stringVal()); + lexer.nextToken(); + } + + } + + int columnSize = 0; + if (lexer.token() == (Token.LPAREN)) { + lexer.nextToken(); + if (lexer.token() == (Token.SELECT)) { + SQLSelect select = this.exprParser.createSelectParser().select(); + select.setParent(insertStatement); + insertStatement.setQuery(select); + } else { + this.exprParser.exprList(insertStatement.getColumns()); + columnSize = insertStatement.getColumns().size(); + } + accept(Token.RPAREN); + } + + if (lexer.token() == Token.VALUES || identifierEquals("VALUE")) { + lexer.nextTokenLParen(); + parseValueClause(insertStatement.getValuesList(), columnSize); + } else if (lexer.token() == Token.SET) { + lexer.nextToken(); + + SQLInsertStatement.ValuesClause values = new SQLInsertStatement.ValuesClause(); + insertStatement.getValuesList().add(values); + + for (;;) { + SQLName name = this.exprParser.name(); + insertStatement.getColumns().add(name); + if (lexer.token() == Token.EQ) { + lexer.nextToken(); + } else { + accept(Token.COLONEQ); + } + values.getValues().add(this.exprParser.expr()); + + if (lexer.token() == Token.COMMA) { + lexer.nextToken(); + continue; + } + + break; + } + + } else if (lexer.token() == (Token.SELECT)) { + SQLSelect select = this.exprParser.createSelectParser().select(); + select.setParent(insertStatement); + insertStatement.setQuery(select); + } else if (lexer.token() == (Token.LPAREN)) { + lexer.nextToken(); + SQLSelect select = this.exprParser.createSelectParser().select(); + select.setParent(insertStatement); + insertStatement.setQuery(select); + accept(Token.RPAREN); + } + + if (lexer.token() == Token.ON) { + lexer.nextToken(); + acceptIdentifier("DUPLICATE"); + accept(Token.KEY); + accept(Token.UPDATE); + + exprParser.exprList(insertStatement.getDuplicateKeyUpdate()); + } + + return insertStatement; + } + + private void parseValueClause(List valueClauseList, int columnSize) { + for (;;) { + if (lexer.token() != Token.LPAREN) { + throw new ParserException("syntax error, expect ')'"); + } + lexer.nextTokenValue(); + + if (lexer.token() != Token.RPAREN) { + List valueExprList; + if (columnSize > 0) { + valueExprList = new ArrayList(columnSize); + } else { + valueExprList = new ArrayList(); + } + + for (;;) { + SQLExpr expr; + if (lexer.token() == Token.LITERAL_INT) { + expr = new SQLIntegerExpr(lexer.integerValue()); + lexer.nextTokenComma(); + } else if (lexer.token() == Token.LITERAL_CHARS) { + expr = new SQLCharExpr(lexer.stringVal()); + lexer.nextTokenComma(); + } else if (lexer.token() == Token.LITERAL_CHARS) { + expr = new SQLCharExpr(lexer.stringVal()); + lexer.nextTokenComma(); + } else { + expr = exprParser.expr(); + } + + if (lexer.token() == Token.COMMA) { + valueExprList.add(expr); + lexer.nextTokenValue(); + continue; + } else if (lexer.token() == Token.RPAREN) { + valueExprList.add(expr); + break; + } else { + expr = this.exprParser.primaryRest(expr); + valueExprList.add(expr); + if (lexer.token() == Token.COMMA) { + lexer.nextToken(); + continue; + } else { + break; + } + } + } + + SQLInsertStatement.ValuesClause values = new SQLInsertStatement.ValuesClause(valueExprList); + valueClauseList.add(values); + } else { + SQLInsertStatement.ValuesClause values = new SQLInsertStatement.ValuesClause(new ArrayList(0)); + valueClauseList.add(values); + } + + if (lexer.token() != Token.RPAREN) { + throw new ParserException("syntax error"); + } + + lexer.nextTokenComma(); + if (lexer.token() == Token.COMMA) { + lexer.nextTokenLParen(); + continue; + } else { + break; + } + } + } + + public SQLStatement parseDropUser() { + acceptIdentifier(USER); + + MySqlDropUser stmt = new MySqlDropUser(); + for (;;) { + SQLExpr expr = this.exprParser.expr(); + stmt.getUsers().add(expr); + if (lexer.token() == Token.COMMA) { + lexer.nextToken(); + continue; + } + break; + } + + return stmt; + } + + protected SQLDropTableStatement parseDropTable(boolean acceptDrop) { + if (acceptDrop) { + accept(Token.DROP); + } + + MySqlDropTableStatement stmt = new MySqlDropTableStatement(); + + if (identifierEquals(TEMPORARY)) { + lexer.nextToken(); + stmt.setTemporary(true); + } + + accept(Token.TABLE); + + if (lexer.token() == Token.IF) { + lexer.nextToken(); + accept(Token.EXISTS); + stmt.setIfExists(true); + } + + for (;;) { + SQLName name = this.exprParser.name(); + stmt.addTableSource(name); + if (lexer.token() == Token.COMMA) { + lexer.nextToken(); + continue; + } + break; + } + + if (identifierEquals(RESTRICT)) { + stmt.setOption(RESTRICT); + lexer.nextToken(); + } else if (identifierEquals(CASCADE)) { + stmt.setOption(CASCADE); + lexer.nextToken(); + } + + return stmt; + } + + protected SQLDropViewStatement parseDropView(boolean acceptDrop) { + if (acceptDrop) { + accept(Token.DROP); + } + + MySqlDropViewStatement stmt = new MySqlDropViewStatement(); + + accept(Token.VIEW); + + if (lexer.token() == Token.IF) { + lexer.nextToken(); + accept(Token.EXISTS); + stmt.setIfExists(true); + } + + for (;;) { + SQLName name = this.exprParser.name(); + stmt.addTableSource(name); + if (lexer.token() == Token.COMMA) { + lexer.nextToken(); + continue; + } + break; + } + + if (identifierEquals(RESTRICT)) { + stmt.setOption(RESTRICT); + lexer.nextToken(); + } else if (identifierEquals(CASCADE)) { + stmt.setOption(CASCADE); + lexer.nextToken(); + } + + return stmt; + } + + public SQLSelectParser createSQLSelectParser() { + return new MySqlSelectParser(this.exprParser); + } + + public SQLStatement parseSet() { + accept(Token.SET); + + Boolean global = null; + if (identifierEquals(GLOBAL)) { + global = Boolean.TRUE; + lexer.nextToken(); + } else if (identifierEquals(SESSION)) { + global = Boolean.FALSE; + lexer.nextToken(); + } + + if (identifierEquals("TRANSACTION")) { + lexer.nextToken(); + acceptIdentifier("ISOLATION"); + acceptIdentifier("LEVEL"); + + MySqlSetTransactionIsolationLevelStatement stmt = new MySqlSetTransactionIsolationLevelStatement(); + stmt.setGlobal(global); + + if (identifierEquals(READ)) { + lexer.nextToken(); + + if (identifierEquals("UNCOMMITTED")) { + stmt.setLevel("READ UNCOMMITTED"); + lexer.nextToken(); + } else if (identifierEquals(WRITE)) { + stmt.setLevel("READ WRITE"); + lexer.nextToken(); + } else if (identifierEquals("ONLY")) { + stmt.setLevel("READ ONLY"); + lexer.nextToken(); + } else if (identifierEquals("COMMITTED")) { + stmt.setLevel("READ COMMITTED"); + lexer.nextToken(); + } else { + throw new ParserException("UNKOWN TRANSACTION LEVEL : " + lexer.stringVal()); + } + } else if (identifierEquals("SERIALIZABLE")) { + stmt.setLevel("SERIALIZABLE"); + lexer.nextToken(); + } else if (identifierEquals("REPEATABLE")) { + lexer.nextToken(); + if (identifierEquals(READ)) { + stmt.setLevel("REPEATABLE READ"); + lexer.nextToken(); + } else { + throw new ParserException("UNKOWN TRANSACTION LEVEL : " + lexer.stringVal()); + } + } else { + throw new ParserException("UNKOWN TRANSACTION LEVEL : " + lexer.stringVal()); + } + + return stmt; + } else if (identifierEquals("NAMES")) { + lexer.nextToken(); + + MySqlSetNamesStatement stmt = new MySqlSetNamesStatement(); + if (lexer.token() == Token.DEFAULT) { + lexer.nextToken(); + stmt.setDefault(true); + } else { + String charSet = lexer.stringVal(); + stmt.setCharSet(charSet); + lexer.nextToken(); + if (identifierEquals(COLLATE2)) { + lexer.nextToken(); + + String collate = lexer.stringVal(); + stmt.setCollate(collate); + lexer.nextToken(); + } + } + return stmt; + } else if (identifierEquals(CHARACTER)) { + lexer.nextToken(); + + accept(Token.SET); + + MySqlSetCharSetStatement stmt = new MySqlSetCharSetStatement(); + if (lexer.token() == Token.DEFAULT) { + lexer.nextToken(); + stmt.setDefault(true); + } else { + String charSet = lexer.stringVal(); + stmt.setCharSet(charSet); + lexer.nextToken(); + if (identifierEquals(COLLATE2)) { + lexer.nextToken(); + + String collate = lexer.stringVal(); + stmt.setCollate(collate); + lexer.nextToken(); + } + } + return stmt; + } else { + SQLSetStatement stmt = new SQLSetStatement(); + + parseAssignItems(stmt.getItems()); + + if (global != null && global.booleanValue()) { + SQLVariantRefExpr varRef = (SQLVariantRefExpr) stmt.getItems().get(0).getTarget(); + varRef.setGlobal(true); + } + + return stmt; + } + } + + public Limit parseLimit() { + return ((MySqlExprParser) this.exprParser).parseLimit(); + } + + public SQLStatement parseAlter() { + accept(Token.ALTER); + + boolean ignore = false; + + if (identifierEquals(IGNORE)) { + ignore = true; + lexer.nextToken(); + } + + if (lexer.token() == Token.TABLE) { + lexer.nextToken(); + + MySqlAlterTableStatement stmt = new MySqlAlterTableStatement(); + stmt.setIgnore(ignore); + stmt.setName(this.exprParser.name()); + + for (;;) { + if (lexer.token() == Token.DROP) { + parseAlterDrop(stmt); + } else if (identifierEquals("ADD")) { + lexer.nextToken(); + + if (identifierEquals("COLUMN")) { + lexer.nextToken(); + MySqlAlterTableAddColumn item = new MySqlAlterTableAddColumn(); + SQLColumnDefinition columnDef = this.exprParser.parseColumn(); + item.getColumns().add(columnDef); + if (identifierEquals("AFTER")) { + lexer.nextToken(); + item.setAfterColumn(this.exprParser.name()); + } else if (identifierEquals("FIRST")) { + lexer.nextToken(); + if (lexer.token() == Token.IDENTIFIER) { + item.setFirstColumn(this.exprParser.name()); + } else { + item.setFirst(true); + } + } + stmt.getItems().add(item); + } else if (lexer.token() == Token.INDEX) { + lexer.nextToken(); + MySqlAlterTableAddIndex item = new MySqlAlterTableAddIndex(); + + if (lexer.token() == Token.LPAREN) { + lexer.nextToken(); + } else { + item.setName(this.exprParser.name()); + accept(Token.LPAREN); + } + + for (;;) { + SQLSelectOrderByItem column = this.exprParser.parseSelectOrderByItem(); + item.getItems().add(column); + if (lexer.token() == Token.COMMA) { + lexer.nextToken(); + continue; + } + break; + } + accept(Token.RPAREN); + + stmt.getItems().add(item); + } else if (lexer.token() == Token.UNIQUE) { + lexer.nextToken(); + + if (lexer.token() == Token.INDEX) { + lexer.nextToken(); + } + + MySqlAlterTableAddUnique item = new MySqlAlterTableAddUnique(); + + if (lexer.token() == Token.LPAREN) { + lexer.nextToken(); + } else { + item.setName(this.exprParser.name()); + accept(Token.LPAREN); + } + + for (;;) { + SQLSelectOrderByItem column = this.exprParser.parseSelectOrderByItem(); + item.getItems().add(column); + if (lexer.token() == Token.COMMA) { + lexer.nextToken(); + continue; + } + break; + } + accept(Token.RPAREN); + + stmt.getItems().add(item); + } else if (lexer.token() == Token.PRIMARY) { + SQLPrimaryKey primaryKey = ((MySqlExprParser) this.exprParser).parsePrimaryKey(); + SQLAlterTableAddPrimaryKey item = new SQLAlterTableAddPrimaryKey(); + item.setPrimaryKey(primaryKey); + stmt.getItems().add(item); + } else if (lexer.token() == Token.KEY) { + throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); + } else if (lexer.token() == Token.CONSTRAINT) { + lexer.nextToken(); + SQLName constraintName = this.exprParser.name(); + + if (lexer.token() == Token.PRIMARY) { + SQLPrimaryKey primaryKey = ((MySqlExprParser) this.exprParser).parsePrimaryKey(); + + primaryKey.setName(constraintName); + + SQLAlterTableAddPrimaryKey item = new SQLAlterTableAddPrimaryKey(); + item.setPrimaryKey(primaryKey); + stmt.getItems().add(item); + } else if (lexer.token() == Token.FOREIGN) { + MySqlForeignKey fk = this.getExprParser().parseForeignKey(); + fk.setName(constraintName); + + SQLAlterTableAddForeignKey item = new SQLAlterTableAddForeignKey(fk); + stmt.getItems().add(item); + } else { + throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); + } + } else if (identifierEquals(FULLTEXT)) { + throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); + } else if (identifierEquals(SPATIAL)) { + throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); + } else { + MySqlAlterTableAddColumn item = new MySqlAlterTableAddColumn(); + SQLColumnDefinition columnDef = this.exprParser.parseColumn(); + item.getColumns().add(columnDef); + if (identifierEquals("AFTER")) { + lexer.nextToken(); + item.setAfterColumn(this.exprParser.name()); + } + stmt.getItems().add(item); + } + } else if (lexer.token() == Token.ALTER) { + lexer.nextToken(); + if (identifierEquals("COLUMN")) { + lexer.nextToken(); + } + + SQLAlterTableAlterColumn alterColumn = new SQLAlterTableAlterColumn(); + SQLColumnDefinition columnDef = this.exprParser.parseColumn(); + alterColumn.setColumn(columnDef); + + stmt.getItems().add(alterColumn); + } else if (identifierEquals("CHANGE")) { + lexer.nextToken(); + if (identifierEquals("COLUMN")) { + lexer.nextToken(); + } + MySqlAlterTableChangeColumn item = new MySqlAlterTableChangeColumn(); + item.setColumnName(this.exprParser.name()); + item.setNewColumnDefinition(this.exprParser.parseColumn()); + if (identifierEquals("AFTER")) { + lexer.nextToken(); + item.setAfterColumn(this.exprParser.name()); + } else if (identifierEquals("FIRST")) { + lexer.nextToken(); + if (lexer.token() == Token.IDENTIFIER) { + item.setFirstColumn(this.exprParser.name()); + } else { + item.setFirst(true); + } + } + stmt.getItems().add(item); + } else if (identifierEquals("MODIFY")) { + lexer.nextToken(); + if (identifierEquals("COLUMN")) { + lexer.nextToken(); + } + MySqlAlterTableModifyColumn item = new MySqlAlterTableModifyColumn(); + item.setNewColumnDefinition(this.exprParser.parseColumn()); + if (identifierEquals("AFTER")) { + lexer.nextToken(); + item.setAfterColumn(this.exprParser.name()); + } else if (identifierEquals("FIRST")) { + lexer.nextToken(); + if (lexer.token() == Token.IDENTIFIER) { + item.setFirstColumn(this.exprParser.name()); + } else { + item.setFirst(true); + } + } + stmt.getItems().add(item); + } else if (identifierEquals("DISABLE")) { + lexer.nextToken(); + + if (lexer.token() == Token.CONSTRAINT) { + lexer.nextToken(); + SQLAlterTableDisableConstraint item = new SQLAlterTableDisableConstraint(); + item.setConstraintName(this.exprParser.name()); + stmt.getItems().add(item); + } else { + acceptIdentifier("KEYS"); + SQLAlterTableDisableKeys item = new SQLAlterTableDisableKeys(); + stmt.getItems().add(item); + } + } else if (identifierEquals("ENABLE")) { + lexer.nextToken(); + if (lexer.token() == Token.CONSTRAINT) { + lexer.nextToken(); + SQLAlterTableEnableConstraint item = new SQLAlterTableEnableConstraint(); + item.setConstraintName(this.exprParser.name()); + stmt.getItems().add(item); + } else { + acceptIdentifier("KEYS"); + SQLAlterTableEnableKeys item = new SQLAlterTableEnableKeys(); + stmt.getItems().add(item); + } + } else if (identifierEquals("RENAME")) { + lexer.nextToken(); + MySqlRenameTableStatement renameStmt = new MySqlRenameTableStatement(); + MySqlRenameTableStatement.Item item = new MySqlRenameTableStatement.Item(); + item.setName(stmt.getTableSource().getExpr()); + item.setTo(this.exprParser.name()); + renameStmt.getItems().add(item); + + return renameStmt; + } else if (lexer.token() == Token.ORDER) { + throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); + } else if (identifierEquals("CONVERT")) { + throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); + } else if (lexer.token() == Token.DEFAULT) { + throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); + } else if (identifierEquals("DISCARD")) { + lexer.nextToken(); + acceptIdentifier("TABLESPACE"); + MySqlAlterTableDiscardTablespace item = new MySqlAlterTableDiscardTablespace(); + stmt.getItems().add(item); + } else if (identifierEquals("IMPORT")) { + lexer.nextToken(); + acceptIdentifier("TABLESPACE"); + MySqlAlterTableImportTablespace item = new MySqlAlterTableImportTablespace(); + stmt.getItems().add(item); + } else if (identifierEquals("FORCE")) { + throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); + } else if (identifierEquals("TRUNCATE")) { + throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); + } else if (identifierEquals("COALESCE")) { + throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); + } else if (identifierEquals("REORGANIZE")) { + throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); + } else if (identifierEquals("EXCHANGE")) { + throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); + } else if (identifierEquals("ANALYZE")) { + throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); + } else if (identifierEquals("CHECK")) { + throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); + } else if (identifierEquals("OPTIMIZE")) { + throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); + } else if (identifierEquals("REBUILD")) { + throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); + } else if (identifierEquals("REPAIR")) { + throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); + } else if (identifierEquals("REMOVE")) { + throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); + } else if (identifierEquals(ENGINE)) { + lexer.nextToken(); + accept(Token.EQ); + stmt.getItems().add(new MySqlAlterTableOption(ENGINE, lexer.stringVal())); + lexer.nextToken(); + } else if (identifierEquals(AUTO_INCREMENT)) { + lexer.nextToken(); + accept(Token.EQ); + stmt.getItems().add(new MySqlAlterTableOption(AUTO_INCREMENT, lexer.integerValue())); + lexer.nextToken(); + } else if (identifierEquals(COLLATE2)) { + lexer.nextToken(); + accept(Token.EQ); + stmt.getItems().add(new MySqlAlterTableOption(COLLATE2, lexer.stringVal())); + lexer.nextToken(); + } else if (identifierEquals("PACK_KEYS")) { + lexer.nextToken(); + accept(Token.EQ); + if (identifierEquals("PACK")) { + lexer.nextToken(); + accept(Token.ALL); + stmt.getItems().add(new MySqlAlterTableOption("PACK_KEYS", "PACK ALL")); + } else { + stmt.getItems().add(new MySqlAlterTableOption("PACK_KEYS", lexer.stringVal())); + lexer.nextToken(); + } + } else if (identifierEquals(CHARACTER)) { + lexer.nextToken(); + accept(Token.SET); + accept(Token.EQ); + MySqlAlterTableCharacter item = new MySqlAlterTableCharacter(); + item.setCharacterSet(this.exprParser.primary()); + if (lexer.token() == Token.COMMA) { + lexer.nextToken(); + acceptIdentifier(COLLATE2); + accept(Token.EQ); + item.setCollate(this.exprParser.primary()); + } + stmt.getItems().add(item); + } else { + break; + } + + if (lexer.token() == Token.COMMA) { + lexer.nextToken(); + continue; + } else { + break; + } + } + + return stmt; + } + throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); + } + + public void parseAlterDrop(SQLAlterTableStatement stmt) { + lexer.nextToken(); + if (lexer.token() == Token.INDEX) { + lexer.nextToken(); + SQLName indexName = this.exprParser.name(); + SQLAlterTableDropIndex item = new SQLAlterTableDropIndex(); + item.setIndexName(indexName); + stmt.getItems().add(item); + } else if (lexer.token() == Token.FOREIGN) { + lexer.nextToken(); + accept(Token.KEY); + SQLName indexName = this.exprParser.name(); + SQLAlterTableDropForeinKey item = new SQLAlterTableDropForeinKey(); + item.setIndexName(indexName); + stmt.getItems().add(item); + } else if (lexer.token() == Token.PRIMARY) { + lexer.nextToken(); + accept(Token.KEY); + SQLAlterTableDropPrimaryKey item = new SQLAlterTableDropPrimaryKey(); + stmt.getItems().add(item); + } else if (lexer.token() == Token.CONSTRAINT) { + lexer.nextToken(); + SQLAlterTableDropConstraint item = new SQLAlterTableDropConstraint(); + item.setConstraintName(this.exprParser.name()); + stmt.getItems().add(item); + } else if (identifierEquals("COLUMN")) { + lexer.nextToken(); + SQLAlterTableDropColumnItem item = new SQLAlterTableDropColumnItem(); + item.setColumnName(this.exprParser.name()); + stmt.getItems().add(item); + } else { + super.parseAlterDrop(stmt); + } + } + + public SQLStatement parseRename() { + MySqlRenameTableStatement stmt = new MySqlRenameTableStatement(); + + acceptIdentifier("RENAME"); + + accept(Token.TABLE); + + for (;;) { + MySqlRenameTableStatement.Item item = new MySqlRenameTableStatement.Item(); + item.setName(this.exprParser.name()); + accept(Token.TO); + item.setTo(this.exprParser.name()); + + stmt.getItems().add(item); + + if (lexer.token() == Token.COMMA) { + lexer.nextToken(); + continue; + } + + break; + } + + return stmt; + } + + public SQLStatement parseCreateDatabase() { + if (lexer.token() == Token.CREATE) { + lexer.nextToken(); + } + + accept(Token.DATABASE); + + SQLCreateDatabaseStatement stmt = new SQLCreateDatabaseStatement(); + stmt.setName(this.exprParser.name()); + + if (lexer.token() == Token.DEFAULT) { + lexer.nextToken(); + } + + return stmt; + } + + protected void parseUpdateSet(SQLUpdateStatement update) { + accept(Token.SET); + + for (;;) { + SQLUpdateSetItem item = new SQLUpdateSetItem(); + + if (lexer.token() == (Token.LPAREN)) { + lexer.nextToken(); + SQLListExpr list = new SQLListExpr(); + this.exprParser.exprList(list.getItems()); + accept(Token.RPAREN); + item.setColumn(list); + } else { + item.setColumn(this.exprParser.primary()); + } + if (lexer.token() == Token.COLONEQ) { + lexer.nextToken(); + } else { + accept(Token.EQ); + } + item.setValue(this.exprParser.expr()); + update.getItems().add(item); + + if (lexer.token() != Token.COMMA) { + break; + } + + lexer.nextToken(); + } + } + + public MySqlExprParser getExprParser() { + return (MySqlExprParser) exprParser; + } +} diff --git a/src/main/java/com/alibaba/druid/wall/WallProvider.java b/src/main/java/com/alibaba/druid/wall/WallProvider.java index d69a530dce..269dfd6789 100644 --- a/src/main/java/com/alibaba/druid/wall/WallProvider.java +++ b/src/main/java/com/alibaba/druid/wall/WallProvider.java @@ -1,710 +1,710 @@ -/* - * Copyright 1999-2011 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.wall; - -import java.security.PrivilegedAction; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.locks.ReentrantReadWriteLock; - -import com.alibaba.druid.sql.ast.SQLStatement; -import com.alibaba.druid.sql.parser.Lexer; -import com.alibaba.druid.sql.parser.NotAllowCommentException; -import com.alibaba.druid.sql.parser.ParserException; -import com.alibaba.druid.sql.parser.SQLStatementParser; -import com.alibaba.druid.sql.parser.Token; -import com.alibaba.druid.sql.visitor.ExportParameterVisitor; -import com.alibaba.druid.util.LRUCache; -import com.alibaba.druid.wall.spi.WallVisitorUtils; -import com.alibaba.druid.wall.violation.ErrorCode; -import com.alibaba.druid.wall.violation.IllegalSQLObjectViolation; -import com.alibaba.druid.wall.violation.SyntaxErrorViolation; - -public abstract class WallProvider { - - private LRUCache whiteList; - - private int MAX_SQL_LENGTH = 2048; // 1k - - private int whiteSqlMaxSize = 500; // 1k - - private LRUCache blackList; - - private int blackSqlMaxSize = 100; // 1k - - protected final WallConfig config; - - private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); - - private static final ThreadLocal privileged = new ThreadLocal(); - - private final ConcurrentMap functionStats = new ConcurrentHashMap(16, 0.75f, 1); - private final ConcurrentMap tableStats = new ConcurrentHashMap(16, 0.75f, 1); - - public final WallDenyStat commentDeniedStat = new WallDenyStat(); - - protected String dbType = null; - protected final AtomicLong checkCount = new AtomicLong(); - protected final AtomicLong hardCheckCount = new AtomicLong(); - protected final AtomicLong whiteListHitCount = new AtomicLong(); - protected final AtomicLong blackListHitCount = new AtomicLong(); - protected final AtomicLong syntaxErrrorCount = new AtomicLong(); - protected final AtomicLong violationCount = new AtomicLong(); - protected final AtomicLong violationEffectRowCount = new AtomicLong(); - - public WallProvider(WallConfig config){ - this.config = config; - } - - public WallProvider(WallConfig config, String dbType){ - this.config = config; - this.dbType = dbType; - } - - public void reset() { - this.checkCount.set(0); - this.hardCheckCount.set(0); - this.violationCount.set(0); - this.whiteListHitCount.set(0); - this.blackListHitCount.set(0); - this.clearWhiteList(); - this.clearBlackList(); - this.functionStats.clear(); - this.tableStats.clear(); - } - - public ConcurrentMap getTableStats() { - return this.tableStats; - } - - public ConcurrentMap getFunctionStats() { - return this.functionStats; - } - - public WallTableStat getTableStat(String tableName) { - String lowerCaseName = tableName.toLowerCase(); - if (lowerCaseName.startsWith("`") && lowerCaseName.endsWith("`")) { - lowerCaseName = lowerCaseName.substring(1, lowerCaseName.length() - 1); - } - - return getTableStatWithLowerName(lowerCaseName); - } - - public WallTableStat getTableStatWithLowerName(String lowerCaseName) { - WallTableStat stat = tableStats.get(lowerCaseName); - if (stat == null) { - if (tableStats.size() > 10000) { - return null; - } - - tableStats.putIfAbsent(lowerCaseName, new WallTableStat()); - stat = tableStats.get(lowerCaseName); - } - return stat; - } - - public WallFunctionStat getFunctionStat(String functionName) { - String lowerCaseName = functionName.toLowerCase(); - return getFunctionStatWithLowerName(lowerCaseName); - } - - public WallFunctionStat getFunctionStatWithLowerName(String lowerCaseName) { - WallFunctionStat stat = functionStats.get(lowerCaseName); - if (stat == null) { - if (functionStats.size() > 10000) { - return null; - } - - functionStats.putIfAbsent(lowerCaseName, new WallFunctionStat()); - stat = functionStats.get(lowerCaseName); - } - return stat; - } - - public WallConfig getConfig() { - return config; - } - - public WallSqlStat addWhiteSql(String sql, Map tableStats, - Map functionStats, boolean syntaxError) { - lock.writeLock().lock(); - try { - if (whiteList == null) { - whiteList = new LRUCache(whiteSqlMaxSize); - } - - WallSqlStat wallStat = whiteList.get(sql); - if (wallStat == null) { - wallStat = new WallSqlStat(tableStats, functionStats, syntaxError); - wallStat.incrementAndGetExecuteCount(); - whiteList.put(sql, wallStat); - } - - return wallStat; - } finally { - lock.writeLock().unlock(); - } - } - - public WallSqlStat addBlackSql(String sql, Map tableStats, - Map functionStats, List violations, - boolean syntaxError) { - lock.writeLock().lock(); - try { - if (blackList == null) { - blackList = new LRUCache(blackSqlMaxSize); - } - - WallSqlStat wallStat = blackList.get(sql); - if (wallStat == null) { - wallStat = new WallSqlStat(tableStats, functionStats, violations, syntaxError); - wallStat.incrementAndGetExecuteCount(); - blackList.put(sql, wallStat); - } - - return wallStat; - } finally { - lock.writeLock().unlock(); - } - } - - public Set getWhiteList() { - Set hashSet = new HashSet(); - lock.readLock().lock(); - try { - if (whiteList != null) { - hashSet.addAll(whiteList.keySet()); - } - } finally { - lock.readLock().unlock(); - } - - return Collections. unmodifiableSet(hashSet); - } - - public Set getBlackList() { - Set hashSet = new HashSet(); - lock.readLock().lock(); - try { - if (blackList != null) { - hashSet.addAll(blackList.keySet()); - } - } finally { - lock.readLock().unlock(); - } - - return Collections. unmodifiableSet(hashSet); - } - - public List> getBlackListStat() { - List> map = new ArrayList>(); - lock.readLock().lock(); - try { - if (blackList != null) { - for (Map.Entry entry : this.blackList.entrySet()) { - WallSqlStat sqlStat = entry.getValue(); - - Map sqlStatMap = new LinkedHashMap(); - sqlStatMap.put("sql", entry.getKey()); - sqlStatMap.put("executeCount", sqlStat.getExecuteCount()); - sqlStatMap.put("effectRowCount", sqlStat.getEffectRowCount()); - - List violations = sqlStat.getViolations(); - if (violations.size() > 0) { - sqlStatMap.put("violationMessage", violations.get(0).getMessage()); - } - - map.add(sqlStatMap); - } - } - } finally { - lock.readLock().unlock(); - } - - return map; - } - - public void clearCache() { - clearWhiteList(); - } - - public void clearWhiteList() { - lock.writeLock().lock(); - try { - if (whiteList != null) { - whiteList = null; - } - } finally { - lock.writeLock().unlock(); - } - } - - public void clearBlackList() { - lock.writeLock().lock(); - try { - if (blackList != null) { - blackList = null; - } - } finally { - lock.writeLock().unlock(); - } - } - - public WallSqlStat getWhiteSql(String sql) { - lock.readLock().lock(); - try { - if (whiteList == null) { - return null; - } - - return whiteList.get(sql); - } finally { - lock.readLock().unlock(); - } - } - - public WallSqlStat getBlackSql(String sql) { - lock.readLock().lock(); - try { - if (blackList == null) { - return null; - } - - return blackList.get(sql); - } finally { - lock.readLock().unlock(); - } - } - - public boolean whiteContains(String sql) { - return getWhiteSql(sql) != null; - } - - public abstract SQLStatementParser createParser(String sql); - - public abstract WallVisitor createWallVisitor(); - - public abstract ExportParameterVisitor createExportParameterVisitor(); - - public boolean checkValid(String sql) { - WallContext originalContext = WallContext.current(); - - try { - WallContext.create(dbType); - WallCheckResult result = checkInternal(sql); - return result.getViolations().isEmpty(); - } finally { - - if (originalContext == null) { - WallContext.clearContext(); - } - } - } - - public void incrementCommentDeniedCount() { - this.commentDeniedStat.incrementAndGetDenyCount(); - } - - public boolean checkDenyFunction(String functionName) { - if (functionName == null) { - return true; - } - - functionName = functionName.toLowerCase(); - - if (getConfig().getDenyFunctions().contains(functionName)) { - return false; - } - - return true; - } - - public boolean checkDenySchema(String schemaName) { - if (schemaName == null) { - return true; - } - - if (!this.config.isSchemaCheck()) { - return true; - } - - schemaName = schemaName.toLowerCase(); - if (getConfig().getDenySchemas().contains(schemaName)) { - return false; - } - - return true; - } - - public boolean checkDenyTable(String tableName) { - if (tableName == null) { - return true; - } - - tableName = WallVisitorUtils.form(tableName); - if (getConfig().getDenyTables().contains(tableName)) { - return false; - } - - return true; - } - - public boolean checkReadOnlyTable(String tableName) { - if (tableName == null) { - return true; - } - - tableName = WallVisitorUtils.form(tableName); - if (getConfig().isReadOnly(tableName)) { - return false; - } - - return true; - } - - public WallDenyStat getCommentDenyStat() { - return this.commentDeniedStat; - } - - public WallCheckResult check(String sql) { - WallContext originalContext = WallContext.current(); - - try { - WallContext.createIfNotExists(dbType); - return checkInternal(sql); - } finally { - if (originalContext == null) { - WallContext.clearContext(); - } - } - } - - private WallCheckResult checkInternal(String sql) { - checkCount.incrementAndGet(); - - WallContext context = WallContext.current(); - - if (config.isDoPrivilegedAllow() && ispPivileged()) { - return new WallCheckResult(); - } - - // first step, check whiteList - boolean mulltiTenant = config.getTenantTablePattern() != null && config.getTenantTablePattern().length() > 0; - if (!mulltiTenant) { - WallCheckResult checkResult = checkWhiteAndBlackList(sql); - if (checkResult != null) { - return checkResult; - } - } - - hardCheckCount.incrementAndGet(); - final List violations = new ArrayList(); - List statementList = new ArrayList(); - boolean syntaxError = false; - try { - SQLStatementParser parser = createParser(sql); - parser.getLexer().setCommentHandler(WallCommentHandler.instance); - - if (!config.isCommentAllow()) { - parser.getLexer().setAllowComment(false); // deny comment - } - - parser.parseStatementList(statementList); - - final Token lastToken = parser.getLexer().token(); - if (lastToken != Token.EOF) { - violations.add(new IllegalSQLObjectViolation(ErrorCode.SYNTAX_ERROR, "not terminal sql, token " - + lastToken, sql)); - } - } catch (NotAllowCommentException e) { - violations.add(new SyntaxErrorViolation(e, sql)); - incrementCommentDeniedCount(); - } catch (ParserException e) { - syntaxErrrorCount.incrementAndGet(); - syntaxError = true; - if (config.isStrictSyntaxCheck()) { - violations.add(new SyntaxErrorViolation(e, sql)); - } - } catch (Exception e) { - violations.add(new SyntaxErrorViolation(e, sql)); - } - - if (statementList.size() > 1 && !config.isMultiStatementAllow()) { - violations.add(new IllegalSQLObjectViolation(ErrorCode.MULTI_STATEMENT, "multi-statement not allow", sql)); - } - - WallVisitor visitor = createWallVisitor(); - - if (statementList.size() > 0) { - SQLStatement stmt = statementList.get(0); - try { - stmt.accept(visitor); - } catch (ParserException e) { - violations.add(new SyntaxErrorViolation(e, sql)); - } - } - - if (visitor.getViolations().size() > 0) { - violations.addAll(visitor.getViolations()); - } - - if (visitor.getViolations().size() == 0 && context != null && context.getWarnnings() >= 2) { - if (context.getDeleteNoneConditionWarnnings() > 0) { - violations.add(new IllegalSQLObjectViolation(ErrorCode.NONE_CONDITION, "delete none condition", sql)); - } else if (context.getUpdateNoneConditionWarnnings() > 0) { - violations.add(new IllegalSQLObjectViolation(ErrorCode.NONE_CONDITION, "update none condition", sql)); - } else if (context.getCommentCount() > 0) { - violations.add(new IllegalSQLObjectViolation(ErrorCode.COMMIT_NOT_ALLOW, "comment not allow", sql)); - } else if (context.getLikeNumberWarnnings() > 0) { - violations.add(new IllegalSQLObjectViolation(ErrorCode.COMMIT_NOT_ALLOW, "like number", sql)); - } else { - violations.add(new IllegalSQLObjectViolation(ErrorCode.COMPOUND, "multi-warnnings", sql)); - } - } - - WallSqlStat sqlStat = null; - if (violations.size() > 0) { - violationCount.incrementAndGet(); - - if (sql.length() < MAX_SQL_LENGTH) { - sqlStat = addBlackSql(sql, context.getTableStats(), context.getFunctionStats(), violations, syntaxError); - } - } else { - if (sql.length() < MAX_SQL_LENGTH) { - sqlStat = addWhiteSql(sql, context.getTableStats(), context.getFunctionStats(), syntaxError); - } - } - - Map tableStats = null; - Map functionStats = null; - if (context != null) { - tableStats = context.getTableStats(); - functionStats = context.getFunctionStats(); - recordStats(tableStats, functionStats); - } - - if (sqlStat != null) { - context.setSqlStat(sqlStat); - return new WallCheckResult(sqlStat, statementList); - } - - return new WallCheckResult(sqlStat, violations, tableStats, functionStats, statementList, syntaxError); - } - - private WallCheckResult checkWhiteAndBlackList(String sql) { - { - WallSqlStat sqlStat = getWhiteSql(sql); - if (sqlStat != null) { - whiteListHitCount.incrementAndGet(); - sqlStat.incrementAndGetExecuteCount(); - - if (sqlStat.isSyntaxError()) { - syntaxErrrorCount.incrementAndGet(); - } - - recordStats(sqlStat.getTableStats(), sqlStat.getFunctionStats()); - WallContext context = WallContext.current(); - if (context != null) { - context.setSqlStat(sqlStat); - } - return new WallCheckResult(sqlStat); - } - } - // check black list - { - WallSqlStat sqlStat = getBlackSql(sql); - if (sqlStat != null) { - blackListHitCount.incrementAndGet(); - violationCount.incrementAndGet(); - - if (sqlStat.isSyntaxError()) { - syntaxErrrorCount.incrementAndGet(); - } - - sqlStat.incrementAndGetExecuteCount(); - recordStats(sqlStat.getTableStats(), sqlStat.getFunctionStats()); - - return new WallCheckResult(sqlStat); - } - } - - return null; - } - - void recordStats(Map tableStats, Map functionStats) { - if (tableStats != null) { - for (Map.Entry entry : tableStats.entrySet()) { - String tableName = entry.getKey(); - WallSqlTableStat sqlTableStat = entry.getValue(); - WallTableStat tableStat = getTableStat(tableName); - if (tableStat != null) { - tableStat.addSqlTableStat(sqlTableStat); - } - } - } - if (functionStats != null) { - for (Map.Entry entry : functionStats.entrySet()) { - String tableName = entry.getKey(); - WallSqlFunctionStat sqlTableStat = entry.getValue(); - WallFunctionStat functionStat = getFunctionStatWithLowerName(tableName); - if (functionStat != null) { - functionStat.addSqlFunctionStat(sqlTableStat); - } - } - } - } - - public static boolean ispPivileged() { - Boolean value = privileged.get(); - if (value == null) { - return false; - } - - return value.booleanValue(); - } - - public static T doPrivileged(PrivilegedAction action) { - final Boolean original = privileged.get(); - privileged.set(Boolean.TRUE); - try { - return action.run(); - } finally { - privileged.set(original); - } - } - - private static final ThreadLocal tenantValueLocal = new ThreadLocal(); - - public static void setTenantValue(Object value) { - tenantValueLocal.set(value); - } - - public static Object getTenantValue() { - return tenantValueLocal.get(); - } - - public long getWhiteListHitCount() { - return whiteListHitCount.get(); - } - - public long getBlackListHitCount() { - return blackListHitCount.get(); - } - - public long getSyntaxErrorCount() { - return syntaxErrrorCount.get(); - } - - public long getCheckCount() { - return checkCount.get(); - } - - public long getViolationCount() { - return violationCount.get(); - } - - public long getHardCheckCount() { - return hardCheckCount.get(); - } - - public long getViolationEffectRowCount() { - return violationEffectRowCount.get(); - } - - public void addViolationEffectRowCount(long rowCount) { - violationEffectRowCount.addAndGet(rowCount); - } - - public static class WallCommentHandler implements Lexer.CommentHandler { - - public final static WallCommentHandler instance = new WallCommentHandler(); - - @Override - public boolean handle(Token lastToken, String comment) { - if (lastToken == null) { - return false; - } - - switch (lastToken) { - case SELECT: - case INSERT: - case DELETE: - case UPDATE: - case TRUNCATE: - case SET: - case CREATE: - case ALTER: - case DROP: - case SHOW: - case REPLACE: - return true; - default: - break; - } - - WallContext context = WallContext.current(); - if (context != null) { - context.incrementCommentCount(); - } - - return false; - } - } - - public Map getStatsMap() { - Map info = new LinkedHashMap(); - - info.put("checkCount", this.getCheckCount()); - info.put("hardCheckCount", this.getHardCheckCount()); - info.put("violationCount", this.getViolationCount()); - info.put("violationEffectRowCount", this.getViolationEffectRowCount()); - info.put("blackListHitCount", this.getBlackListHitCount()); - info.put("blackListSize", this.getBlackList().size()); - info.put("whiteListHitCount", this.getWhiteListHitCount()); - info.put("whiteListSize", this.getWhiteList().size()); - info.put("syntaxErrrorCount", this.getSyntaxErrorCount()); - - { - List> tables = new ArrayList>(); - for (Map.Entry entry : this.tableStats.entrySet()) { - Map statMap = entry.getValue().toMap(); - statMap.put("name", entry.getKey()); - tables.add(statMap); - } - info.put("tables", tables); - } - { - List> functions = new ArrayList>(); - for (Map.Entry entry : this.functionStats.entrySet()) { - Map statMap = entry.getValue().toMap(); - statMap.put("name", entry.getKey()); - functions.add(statMap); - } - info.put("functions", functions); - } - // info.put("whiteList", this.getWhiteList()); - info.put("blackList", this.getBlackListStat()); - return info; - } -} +/* + * Copyright 1999-2011 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.wall; + +import java.security.PrivilegedAction; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.parser.Lexer; +import com.alibaba.druid.sql.parser.NotAllowCommentException; +import com.alibaba.druid.sql.parser.ParserException; +import com.alibaba.druid.sql.parser.SQLStatementParser; +import com.alibaba.druid.sql.parser.Token; +import com.alibaba.druid.sql.visitor.ExportParameterVisitor; +import com.alibaba.druid.util.LRUCache; +import com.alibaba.druid.wall.spi.WallVisitorUtils; +import com.alibaba.druid.wall.violation.ErrorCode; +import com.alibaba.druid.wall.violation.IllegalSQLObjectViolation; +import com.alibaba.druid.wall.violation.SyntaxErrorViolation; + +public abstract class WallProvider { + + private LRUCache whiteList; + + private int MAX_SQL_LENGTH = 2048; // 1k + + private int whiteSqlMaxSize = 500; // 1k + + private LRUCache blackList; + + private int blackSqlMaxSize = 100; // 1k + + protected final WallConfig config; + + private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); + + private static final ThreadLocal privileged = new ThreadLocal(); + + private final ConcurrentMap functionStats = new ConcurrentHashMap(16, 0.75f, 1); + private final ConcurrentMap tableStats = new ConcurrentHashMap(16, 0.75f, 1); + + public final WallDenyStat commentDeniedStat = new WallDenyStat(); + + protected String dbType = null; + protected final AtomicLong checkCount = new AtomicLong(); + protected final AtomicLong hardCheckCount = new AtomicLong(); + protected final AtomicLong whiteListHitCount = new AtomicLong(); + protected final AtomicLong blackListHitCount = new AtomicLong(); + protected final AtomicLong syntaxErrrorCount = new AtomicLong(); + protected final AtomicLong violationCount = new AtomicLong(); + protected final AtomicLong violationEffectRowCount = new AtomicLong(); + + public WallProvider(WallConfig config){ + this.config = config; + } + + public WallProvider(WallConfig config, String dbType){ + this.config = config; + this.dbType = dbType; + } + + public void reset() { + this.checkCount.set(0); + this.hardCheckCount.set(0); + this.violationCount.set(0); + this.whiteListHitCount.set(0); + this.blackListHitCount.set(0); + this.clearWhiteList(); + this.clearBlackList(); + this.functionStats.clear(); + this.tableStats.clear(); + } + + public ConcurrentMap getTableStats() { + return this.tableStats; + } + + public ConcurrentMap getFunctionStats() { + return this.functionStats; + } + + public WallTableStat getTableStat(String tableName) { + String lowerCaseName = tableName.toLowerCase(); + if (lowerCaseName.startsWith("`") && lowerCaseName.endsWith("`")) { + lowerCaseName = lowerCaseName.substring(1, lowerCaseName.length() - 1); + } + + return getTableStatWithLowerName(lowerCaseName); + } + + public WallTableStat getTableStatWithLowerName(String lowerCaseName) { + WallTableStat stat = tableStats.get(lowerCaseName); + if (stat == null) { + if (tableStats.size() > 10000) { + return null; + } + + tableStats.putIfAbsent(lowerCaseName, new WallTableStat()); + stat = tableStats.get(lowerCaseName); + } + return stat; + } + + public WallFunctionStat getFunctionStat(String functionName) { + String lowerCaseName = functionName.toLowerCase(); + return getFunctionStatWithLowerName(lowerCaseName); + } + + public WallFunctionStat getFunctionStatWithLowerName(String lowerCaseName) { + WallFunctionStat stat = functionStats.get(lowerCaseName); + if (stat == null) { + if (functionStats.size() > 10000) { + return null; + } + + functionStats.putIfAbsent(lowerCaseName, new WallFunctionStat()); + stat = functionStats.get(lowerCaseName); + } + return stat; + } + + public WallConfig getConfig() { + return config; + } + + public WallSqlStat addWhiteSql(String sql, Map tableStats, + Map functionStats, boolean syntaxError) { + lock.writeLock().lock(); + try { + if (whiteList == null) { + whiteList = new LRUCache(whiteSqlMaxSize); + } + + WallSqlStat wallStat = whiteList.get(sql); + if (wallStat == null) { + wallStat = new WallSqlStat(tableStats, functionStats, syntaxError); + wallStat.incrementAndGetExecuteCount(); + whiteList.put(sql, wallStat); + } + + return wallStat; + } finally { + lock.writeLock().unlock(); + } + } + + public WallSqlStat addBlackSql(String sql, Map tableStats, + Map functionStats, List violations, + boolean syntaxError) { + lock.writeLock().lock(); + try { + if (blackList == null) { + blackList = new LRUCache(blackSqlMaxSize); + } + + WallSqlStat wallStat = blackList.get(sql); + if (wallStat == null) { + wallStat = new WallSqlStat(tableStats, functionStats, violations, syntaxError); + wallStat.incrementAndGetExecuteCount(); + blackList.put(sql, wallStat); + } + + return wallStat; + } finally { + lock.writeLock().unlock(); + } + } + + public Set getWhiteList() { + Set hashSet = new HashSet(); + lock.readLock().lock(); + try { + if (whiteList != null) { + hashSet.addAll(whiteList.keySet()); + } + } finally { + lock.readLock().unlock(); + } + + return Collections. unmodifiableSet(hashSet); + } + + public Set getBlackList() { + Set hashSet = new HashSet(); + lock.readLock().lock(); + try { + if (blackList != null) { + hashSet.addAll(blackList.keySet()); + } + } finally { + lock.readLock().unlock(); + } + + return Collections. unmodifiableSet(hashSet); + } + + public List> getBlackListStat() { + List> map = new ArrayList>(); + lock.readLock().lock(); + try { + if (blackList != null) { + for (Map.Entry entry : this.blackList.entrySet()) { + WallSqlStat sqlStat = entry.getValue(); + + Map sqlStatMap = new LinkedHashMap(); + sqlStatMap.put("sql", entry.getKey()); + sqlStatMap.put("executeCount", sqlStat.getExecuteCount()); + sqlStatMap.put("effectRowCount", sqlStat.getEffectRowCount()); + + List violations = sqlStat.getViolations(); + if (violations.size() > 0) { + sqlStatMap.put("violationMessage", violations.get(0).getMessage()); + } + + map.add(sqlStatMap); + } + } + } finally { + lock.readLock().unlock(); + } + + return map; + } + + public void clearCache() { + clearWhiteList(); + } + + public void clearWhiteList() { + lock.writeLock().lock(); + try { + if (whiteList != null) { + whiteList = null; + } + } finally { + lock.writeLock().unlock(); + } + } + + public void clearBlackList() { + lock.writeLock().lock(); + try { + if (blackList != null) { + blackList = null; + } + } finally { + lock.writeLock().unlock(); + } + } + + public WallSqlStat getWhiteSql(String sql) { + lock.readLock().lock(); + try { + if (whiteList == null) { + return null; + } + + return whiteList.get(sql); + } finally { + lock.readLock().unlock(); + } + } + + public WallSqlStat getBlackSql(String sql) { + lock.readLock().lock(); + try { + if (blackList == null) { + return null; + } + + return blackList.get(sql); + } finally { + lock.readLock().unlock(); + } + } + + public boolean whiteContains(String sql) { + return getWhiteSql(sql) != null; + } + + public abstract SQLStatementParser createParser(String sql); + + public abstract WallVisitor createWallVisitor(); + + public abstract ExportParameterVisitor createExportParameterVisitor(); + + public boolean checkValid(String sql) { + WallContext originalContext = WallContext.current(); + + try { + WallContext.create(dbType); + WallCheckResult result = checkInternal(sql); + return result.getViolations().isEmpty(); + } finally { + + if (originalContext == null) { + WallContext.clearContext(); + } + } + } + + public void incrementCommentDeniedCount() { + this.commentDeniedStat.incrementAndGetDenyCount(); + } + + public boolean checkDenyFunction(String functionName) { + if (functionName == null) { + return true; + } + + functionName = functionName.toLowerCase(); + + if (getConfig().getDenyFunctions().contains(functionName)) { + return false; + } + + return true; + } + + public boolean checkDenySchema(String schemaName) { + if (schemaName == null) { + return true; + } + + if (!this.config.isSchemaCheck()) { + return true; + } + + schemaName = schemaName.toLowerCase(); + if (getConfig().getDenySchemas().contains(schemaName)) { + return false; + } + + return true; + } + + public boolean checkDenyTable(String tableName) { + if (tableName == null) { + return true; + } + + tableName = WallVisitorUtils.form(tableName); + if (getConfig().getDenyTables().contains(tableName)) { + return false; + } + + return true; + } + + public boolean checkReadOnlyTable(String tableName) { + if (tableName == null) { + return true; + } + + tableName = WallVisitorUtils.form(tableName); + if (getConfig().isReadOnly(tableName)) { + return false; + } + + return true; + } + + public WallDenyStat getCommentDenyStat() { + return this.commentDeniedStat; + } + + public WallCheckResult check(String sql) { + WallContext originalContext = WallContext.current(); + + try { + WallContext.createIfNotExists(dbType); + return checkInternal(sql); + } finally { + if (originalContext == null) { + WallContext.clearContext(); + } + } + } + + private WallCheckResult checkInternal(String sql) { + checkCount.incrementAndGet(); + + WallContext context = WallContext.current(); + + if (config.isDoPrivilegedAllow() && ispPivileged()) { + return new WallCheckResult(); + } + + // first step, check whiteList + boolean mulltiTenant = config.getTenantTablePattern() != null && config.getTenantTablePattern().length() > 0; + if (!mulltiTenant) { + WallCheckResult checkResult = checkWhiteAndBlackList(sql); + if (checkResult != null) { + return checkResult; + } + } + + hardCheckCount.incrementAndGet(); + final List violations = new ArrayList(); + List statementList = new ArrayList(); + boolean syntaxError = false; + try { + SQLStatementParser parser = createParser(sql); + parser.getLexer().setCommentHandler(WallCommentHandler.instance); + + if (!config.isCommentAllow()) { + parser.getLexer().setAllowComment(false); // deny comment + } + + parser.parseStatementList(statementList); + + final Token lastToken = parser.getLexer().token(); + if (lastToken != Token.EOF) { + violations.add(new IllegalSQLObjectViolation(ErrorCode.SYNTAX_ERROR, "not terminal sql, token " + + lastToken, sql)); + } + } catch (NotAllowCommentException e) { + violations.add(new SyntaxErrorViolation(e, sql)); + incrementCommentDeniedCount(); + } catch (ParserException e) { + syntaxErrrorCount.incrementAndGet(); + syntaxError = true; + if (config.isStrictSyntaxCheck()) { + violations.add(new SyntaxErrorViolation(e, sql)); + } + } catch (Exception e) { + violations.add(new SyntaxErrorViolation(e, sql)); + } + + if (statementList.size() > 1 && !config.isMultiStatementAllow()) { + violations.add(new IllegalSQLObjectViolation(ErrorCode.MULTI_STATEMENT, "multi-statement not allow", sql)); + } + + WallVisitor visitor = createWallVisitor(); + + if (statementList.size() > 0) { + SQLStatement stmt = statementList.get(0); + try { + stmt.accept(visitor); + } catch (ParserException e) { + violations.add(new SyntaxErrorViolation(e, sql)); + } + } + + if (visitor.getViolations().size() > 0) { + violations.addAll(visitor.getViolations()); + } + + if (visitor.getViolations().size() == 0 && context != null && context.getWarnnings() >= 2) { + if (context.getDeleteNoneConditionWarnnings() > 0) { + violations.add(new IllegalSQLObjectViolation(ErrorCode.NONE_CONDITION, "delete none condition", sql)); + } else if (context.getUpdateNoneConditionWarnnings() > 0) { + violations.add(new IllegalSQLObjectViolation(ErrorCode.NONE_CONDITION, "update none condition", sql)); + } else if (context.getCommentCount() > 0) { + violations.add(new IllegalSQLObjectViolation(ErrorCode.COMMIT_NOT_ALLOW, "comment not allow", sql)); + } else if (context.getLikeNumberWarnnings() > 0) { + violations.add(new IllegalSQLObjectViolation(ErrorCode.COMMIT_NOT_ALLOW, "like number", sql)); + } else { + violations.add(new IllegalSQLObjectViolation(ErrorCode.COMPOUND, "multi-warnnings", sql)); + } + } + + WallSqlStat sqlStat = null; + if (violations.size() > 0) { + violationCount.incrementAndGet(); + + if (sql.length() < MAX_SQL_LENGTH) { + sqlStat = addBlackSql(sql, context.getTableStats(), context.getFunctionStats(), violations, syntaxError); + } + } else { + if (sql.length() < MAX_SQL_LENGTH) { + sqlStat = addWhiteSql(sql, context.getTableStats(), context.getFunctionStats(), syntaxError); + } + } + + Map tableStats = null; + Map functionStats = null; + if (context != null) { + tableStats = context.getTableStats(); + functionStats = context.getFunctionStats(); + recordStats(tableStats, functionStats); + } + + if (sqlStat != null) { + context.setSqlStat(sqlStat); + return new WallCheckResult(sqlStat, statementList); + } + + return new WallCheckResult(sqlStat, violations, tableStats, functionStats, statementList, syntaxError); + } + + private WallCheckResult checkWhiteAndBlackList(String sql) { + { + WallSqlStat sqlStat = getWhiteSql(sql); + if (sqlStat != null) { + whiteListHitCount.incrementAndGet(); + sqlStat.incrementAndGetExecuteCount(); + + if (sqlStat.isSyntaxError()) { + syntaxErrrorCount.incrementAndGet(); + } + + recordStats(sqlStat.getTableStats(), sqlStat.getFunctionStats()); + WallContext context = WallContext.current(); + if (context != null) { + context.setSqlStat(sqlStat); + } + return new WallCheckResult(sqlStat); + } + } + // check black list + { + WallSqlStat sqlStat = getBlackSql(sql); + if (sqlStat != null) { + blackListHitCount.incrementAndGet(); + violationCount.incrementAndGet(); + + if (sqlStat.isSyntaxError()) { + syntaxErrrorCount.incrementAndGet(); + } + + sqlStat.incrementAndGetExecuteCount(); + recordStats(sqlStat.getTableStats(), sqlStat.getFunctionStats()); + + return new WallCheckResult(sqlStat); + } + } + + return null; + } + + void recordStats(Map tableStats, Map functionStats) { + if (tableStats != null) { + for (Map.Entry entry : tableStats.entrySet()) { + String tableName = entry.getKey(); + WallSqlTableStat sqlTableStat = entry.getValue(); + WallTableStat tableStat = getTableStat(tableName); + if (tableStat != null) { + tableStat.addSqlTableStat(sqlTableStat); + } + } + } + if (functionStats != null) { + for (Map.Entry entry : functionStats.entrySet()) { + String tableName = entry.getKey(); + WallSqlFunctionStat sqlTableStat = entry.getValue(); + WallFunctionStat functionStat = getFunctionStatWithLowerName(tableName); + if (functionStat != null) { + functionStat.addSqlFunctionStat(sqlTableStat); + } + } + } + } + + public static boolean ispPivileged() { + Boolean value = privileged.get(); + if (value == null) { + return false; + } + + return value.booleanValue(); + } + + public static T doPrivileged(PrivilegedAction action) { + final Boolean original = privileged.get(); + privileged.set(Boolean.TRUE); + try { + return action.run(); + } finally { + privileged.set(original); + } + } + + private static final ThreadLocal tenantValueLocal = new ThreadLocal(); + + public static void setTenantValue(Object value) { + tenantValueLocal.set(value); + } + + public static Object getTenantValue() { + return tenantValueLocal.get(); + } + + public long getWhiteListHitCount() { + return whiteListHitCount.get(); + } + + public long getBlackListHitCount() { + return blackListHitCount.get(); + } + + public long getSyntaxErrorCount() { + return syntaxErrrorCount.get(); + } + + public long getCheckCount() { + return checkCount.get(); + } + + public long getViolationCount() { + return violationCount.get(); + } + + public long getHardCheckCount() { + return hardCheckCount.get(); + } + + public long getViolationEffectRowCount() { + return violationEffectRowCount.get(); + } + + public void addViolationEffectRowCount(long rowCount) { + violationEffectRowCount.addAndGet(rowCount); + } + + public static class WallCommentHandler implements Lexer.CommentHandler { + + public final static WallCommentHandler instance = new WallCommentHandler(); + + @Override + public boolean handle(Token lastToken, String comment) { + if (lastToken == null) { + return false; + } + + switch (lastToken) { + case SELECT: + case INSERT: + case DELETE: + case UPDATE: + case TRUNCATE: + case SET: + case CREATE: + case ALTER: + case DROP: + case SHOW: + case REPLACE: + return true; + default: + break; + } + + WallContext context = WallContext.current(); + if (context != null) { + context.incrementCommentCount(); + } + + return false; + } + } + + public Map getStatsMap() { + Map info = new LinkedHashMap(); + + info.put("checkCount", this.getCheckCount()); + info.put("hardCheckCount", this.getHardCheckCount()); + info.put("violationCount", this.getViolationCount()); + info.put("violationEffectRowCount", this.getViolationEffectRowCount()); + info.put("blackListHitCount", this.getBlackListHitCount()); + info.put("blackListSize", this.getBlackList().size()); + info.put("whiteListHitCount", this.getWhiteListHitCount()); + info.put("whiteListSize", this.getWhiteList().size()); + info.put("syntaxErrrorCount", this.getSyntaxErrorCount()); + + { + List> tables = new ArrayList>(); + for (Map.Entry entry : this.tableStats.entrySet()) { + Map statMap = entry.getValue().toMap(); + statMap.put("name", entry.getKey()); + tables.add(statMap); + } + info.put("tables", tables); + } + { + List> functions = new ArrayList>(); + for (Map.Entry entry : this.functionStats.entrySet()) { + Map statMap = entry.getValue().toMap(); + statMap.put("name", entry.getKey()); + functions.add(statMap); + } + info.put("functions", functions); + } + // info.put("whiteList", this.getWhiteList()); + info.put("blackList", this.getBlackListStat()); + return info; + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/filter/wall/MySqlWallTest93.java b/src/test/java/com/alibaba/druid/bvt/filter/wall/MySqlWallTest93.java index 65101b845e..b6a73fb6d2 100644 --- a/src/test/java/com/alibaba/druid/bvt/filter/wall/MySqlWallTest93.java +++ b/src/test/java/com/alibaba/druid/bvt/filter/wall/MySqlWallTest93.java @@ -34,7 +34,7 @@ public class MySqlWallTest93 extends TestCase { public void test_false() throws Exception { WallProvider provider = new MySqlWallProvider(); - Assert.assertFalse(provider.checkValid(// + Assert.assertTrue(provider.checkValid(// "desc tablename")); Assert.assertEquals(0, provider.getTableStats().size()); diff --git a/src/test/java/com/alibaba/druid/bvt/filter/wall/MySqlWallTest94.java b/src/test/java/com/alibaba/druid/bvt/filter/wall/MySqlWallTest94.java new file mode 100644 index 0000000000..323746c981 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/filter/wall/MySqlWallTest94.java @@ -0,0 +1,43 @@ +/* + * Copyright 1999-2011 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.bvt.filter.wall; + +import junit.framework.TestCase; + +import org.junit.Assert; + +import com.alibaba.druid.wall.WallProvider; +import com.alibaba.druid.wall.spi.MySqlWallProvider; + +/** + * SQLServerWallTest + * + * @author RaymondXiu + * @version 1.0, 2012-3-18 + * @see + */ +public class MySqlWallTest94 extends TestCase { + + public void test_false() throws Exception { + WallProvider provider = new MySqlWallProvider(); + + Assert.assertTrue(provider.checkValid(// + "select * from test having 1=1")); + + Assert.assertEquals(1, provider.getTableStats().size()); + } + +}