diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlUpdateStatement.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlUpdateStatement.java index d3dd6936d9..e12d7f3c9e 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlUpdateStatement.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/statement/MySqlUpdateStatement.java @@ -1,22 +1,28 @@ package com.alibaba.druid.sql.dialect.mysql.ast.statement; +import com.alibaba.druid.sql.ast.SQLOrderBy; import com.alibaba.druid.sql.ast.statement.SQLUpdateStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock.Limit; import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlASTVisitor; import com.alibaba.druid.sql.visitor.SQLASTVisitor; public class MySqlUpdateStatement extends SQLUpdateStatement implements MySqlStatement { - private static final long serialVersionUID = 1L; - private Limit limit; - public Limit getLimit() { - return limit; - } + private static final long serialVersionUID = 1L; + private SQLOrderBy orderBy; + private Limit limit; + + private boolean lowPriority = false; + private boolean ignore = false; + + public Limit getLimit() { + return limit; + } + + public void setLimit(Limit limit) { + this.limit = limit; + } - public void setLimit(Limit limit) { - this.limit = limit; - } - @Override protected void accept0(SQLASTVisitor visitor) { if (visitor instanceof MySqlASTVisitor) { @@ -26,13 +32,39 @@ public class MySqlUpdateStatement extends SQLUpdateStatement implements MySqlSta } } - public void accept0(MySqlASTVisitor visitor) { - if (visitor.visit(this)) { - acceptChild(visitor, tableSource); - acceptChild(visitor, items); - acceptChild(visitor, where); - acceptChild(visitor, limit); - } - visitor.endVisit(this); - } + public void accept0(MySqlASTVisitor visitor) { + if (visitor.visit(this)) { + acceptChild(visitor, tableSource); + acceptChild(visitor, items); + acceptChild(visitor, where); + acceptChild(visitor, orderBy); + acceptChild(visitor, limit); + } + visitor.endVisit(this); + } + + public boolean isLowPriority() { + return lowPriority; + } + + public void setLowPriority(boolean lowPriority) { + this.lowPriority = lowPriority; + } + + public boolean isIgnore() { + return ignore; + } + + public void setIgnore(boolean ignore) { + this.ignore = ignore; + } + + public SQLOrderBy getOrderBy() { + return orderBy; + } + + public void setOrderBy(SQLOrderBy orderBy) { + this.orderBy = orderBy; + } + } 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 42b234cfe0..07ff99633d 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 @@ -23,7 +23,9 @@ 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.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; @@ -260,42 +262,49 @@ public class MySqlSelectParser extends SQLSelectParser { if (identifierEquals("USE")) { lexer.nextToken(); MySqlUseIndexHint hint = new MySqlUseIndexHint(); - 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); - this.createExprParser().names(hint.getIndexList()); - accept(Token.RPAREN); + parseIndexHint(hint); tableSource.getHints().add(hint); } if (identifierEquals("IGNORE")) { - throw new ParserException("TODO"); + lexer.nextToken(); + MySqlIgnoreIndexHint hint = new MySqlIgnoreIndexHint(); + 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); + this.createExprParser().names(hint.getIndexList()); + accept(Token.RPAREN); + } + protected MySqlUnionQuery createSQLUnionQuery() { return new MySqlUnionQuery(); } 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 82197c7b16..157acc1938 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 @@ -36,6 +36,7 @@ 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.statement.CobarShowStatus; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlAlterTableAddColumn; @@ -137,7 +138,53 @@ public class MySqlStatementParser extends SQLStatementParser { } public SQLUpdateStatement parseUpdateStatement() throws ParserException { - MySqlUpdateStatement stmt = (MySqlUpdateStatement) super.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); + } + + accept(Token.SET); + + for (;;) { + SQLUpdateSetItem item = new SQLUpdateSetItem(); + item.setColumn(this.exprParser.name()); + if (lexer.token() == Token.EQ) { + lexer.nextToken(); + } else { + accept(Token.COLONEQ); + } + item.setValue(this.exprParser.expr()); + + stmt.getItems().add(item); + + if (lexer.token() == (Token.COMMA)) { + lexer.nextToken(); + continue; + } + + break; + } + + if (lexer.token() == (Token.WHERE)) { + lexer.nextToken(); + stmt.setWhere(this.exprParser.expr()); + } + + stmt.setOrderBy(this.exprParser.parseOrderBy()); stmt.setLimit(parseLimit()); diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlASTVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlASTVisitor.java index 36f8444a57..0a29239179 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlASTVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlASTVisitor.java @@ -15,6 +15,7 @@ */ package com.alibaba.druid.sql.dialect.mysql.visitor; +import com.alibaba.druid.sql.dialect.mysql.ast.MySqlIgnoreIndexHint; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlKey; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlPrimaryKey; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlUseIndexHint; @@ -455,4 +456,8 @@ public interface MySqlASTVisitor extends SQLASTVisitor { boolean visit(MySqlUseIndexHint x); void endVisit(MySqlUseIndexHint x); + + boolean visit(MySqlIgnoreIndexHint x); + + void endVisit(MySqlIgnoreIndexHint x); } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlASTVisitorAdapter.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlASTVisitorAdapter.java index ccb5d24152..090358c0ad 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlASTVisitorAdapter.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlASTVisitorAdapter.java @@ -1,5 +1,6 @@ package com.alibaba.druid.sql.dialect.mysql.visitor; +import com.alibaba.druid.sql.dialect.mysql.ast.MySqlIgnoreIndexHint; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlKey; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlPrimaryKey; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlUseIndexHint; @@ -991,4 +992,14 @@ public class MySqlASTVisitorAdapter extends SQLASTVisitorAdapter implements public void endVisit(MySqlUseIndexHint x) { } + + @Override + public boolean visit(MySqlIgnoreIndexHint x) { + return true; + } + + @Override + public void endVisit(MySqlIgnoreIndexHint x) { + + } } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlOutputVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlOutputVisitor.java index f7c9a1c8b5..50bcaf8448 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlOutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlOutputVisitor.java @@ -32,6 +32,7 @@ import com.alibaba.druid.sql.ast.statement.SQLCreateTableStatement; import com.alibaba.druid.sql.ast.statement.SQLExprTableSource; import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock; import com.alibaba.druid.sql.ast.statement.SQLUpdateStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.MySqlIgnoreIndexHint; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlKey; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlPrimaryKey; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlUseIndexHint; @@ -1463,7 +1464,39 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV @Override public boolean visit(MySqlUpdateStatement x) { - super.visit((SQLUpdateStatement) x); + print("UPDATE "); + + if (x.isLowPriority()) { + print("LOW_PRIORITY "); + } + + if (x.isIgnore()) { + print("IGNORE "); + } + + x.getTableSource().accept(this); + + println(); + print("SET "); + for (int i = 0, size = x.getItems().size(); i < size; ++i) { + if (i != 0) { + print(", "); + } + x.getItems().get(i).accept(this); + } + + if (x.getWhere() != null) { + println(); + print("WHERE "); + x.getWhere().setParent(x); + x.getWhere().accept(this); + } + + if (x.getOrderBy() != null) { + println(); + x.getOrderBy().accept(this); + } + if (x.getLimit() != null) { println(); x.getLimit().accept(this); @@ -2372,6 +2405,25 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV @Override public void endVisit(MySqlUseIndexHint x) { + } + + @Override + public boolean visit(MySqlIgnoreIndexHint x) { + print("IGNORE INDEX "); + if (x.getOption() != null) { + print("FOR "); + print(x.getOption().name); + print(' '); + } + print('('); + printAndAccept(x.getIndexList(), ", "); + print(')'); + return false; + } + + @Override + public void endVisit(MySqlIgnoreIndexHint x) { + } public boolean visit(SQLExprTableSource x) { diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlSchemaStatVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlSchemaStatVisitor.java index 2b4966a1d1..5b31abced1 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlSchemaStatVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlSchemaStatVisitor.java @@ -10,6 +10,7 @@ import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock; import com.alibaba.druid.sql.ast.statement.SQLSelectStatement; import com.alibaba.druid.sql.ast.statement.SQLUnionQuery; import com.alibaba.druid.sql.ast.statement.SQLUpdateStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.MySqlIgnoreIndexHint; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlKey; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlPrimaryKey; import com.alibaba.druid.sql.dialect.mysql.ast.MySqlUseIndexHint; @@ -1055,4 +1056,14 @@ public class MySqlSchemaStatVisitor extends SchemaStatVisitor implements MySqlAS public void endVisit(MySqlUseIndexHint x) { } + + @Override + public boolean visit(MySqlIgnoreIndexHint x) { + return false; + } + + @Override + public void endVisit(MySqlIgnoreIndexHint x) { + + } } diff --git a/src/main/java/com/alibaba/druid/sql/parser/SQLSelectParser.java b/src/main/java/com/alibaba/druid/sql/parser/SQLSelectParser.java index 22dd626c18..c247171e2a 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/SQLSelectParser.java +++ b/src/main/java/com/alibaba/druid/sql/parser/SQLSelectParser.java @@ -223,8 +223,10 @@ public class SQLSelectParser extends SQLParser { } else if (lexer.token() == Token.LPAREN) { tableSource = parseTableSource(); accept(Token.RPAREN); + accept(Token.RPAREN); } else { - throw new ParserException("TODO"); + tableSource = parseTableSource(); + accept(Token.RPAREN); } return parseTableSourceRest(tableSource); diff --git a/src/main/java/com/alibaba/druid/sql/parser/SQLStatementParser.java b/src/main/java/com/alibaba/druid/sql/parser/SQLStatementParser.java index 29dba343fb..2260d695ef 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/SQLStatementParser.java +++ b/src/main/java/com/alibaba/druid/sql/parser/SQLStatementParser.java @@ -34,6 +34,7 @@ import com.alibaba.druid.sql.ast.statement.SQLDropViewStatement; import com.alibaba.druid.sql.ast.statement.SQLExprTableSource; import com.alibaba.druid.sql.ast.statement.SQLInsertInto; import com.alibaba.druid.sql.ast.statement.SQLInsertStatement; +import com.alibaba.druid.sql.ast.statement.SQLSavePointStatement; import com.alibaba.druid.sql.ast.statement.SQLSelectStatement; import com.alibaba.druid.sql.ast.statement.SQLSetStatement; import com.alibaba.druid.sql.ast.statement.SQLTableSource; @@ -158,17 +159,23 @@ public class SQLStatementParser extends SQLParser { statementList.add(stmt); continue; } - + if (identifierEquals("RENAME")) { SQLStatement stmt = parseRename(); statementList.add(stmt); continue; } + if (identifierEquals("SAVEPOINT")) { + SQLStatement stmt = parseSavePoint(); + statementList.add(stmt); + continue; + } + if (parseStatementListDialect(statementList)) { continue; } - + if (lexer.token() == Token.LPAREN) { char mark_ch = lexer.current(); int mark_bp = lexer.bp(); @@ -192,11 +199,18 @@ public class SQLStatementParser extends SQLParser { return stmt; } + public SQLStatement parseSavePoint() { + acceptIdentifier("SAVEPOINT"); + SQLSavePointStatement stmt = new SQLSavePointStatement(); + stmt.setName(this.exprParser.name()); + return stmt; + } + public SQLStatement parseAlter() { accept(Token.ALTER); throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); } - + public SQLStatement parseRename() { throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal()); } @@ -220,15 +234,15 @@ public class SQLStatementParser extends SQLParser { } return stmt; } - + protected SQLDropViewStatement parseDropView(boolean acceptDrop) { if (acceptDrop) { accept(Token.DROP); } accept(Token.VIEW); - + SQLDropViewStatement stmt = new SQLDropViewStatement(); - + for (;;) { SQLName name = this.exprParser.name(); stmt.getTableSources().add(new SQLExprTableSource(name)); diff --git a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java index 73800481ef..99110aa053 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java @@ -69,6 +69,7 @@ import com.alibaba.druid.sql.ast.statement.SQLDropTableStatement; import com.alibaba.druid.sql.ast.statement.SQLDropViewStatement; import com.alibaba.druid.sql.ast.statement.SQLExprTableSource; import com.alibaba.druid.sql.ast.statement.SQLInsertStatement; +import com.alibaba.druid.sql.ast.statement.SQLSavePointStatement; import com.alibaba.druid.sql.ast.statement.SQLInsertStatement.ValuesClause; import com.alibaba.druid.sql.ast.statement.SQLJoinTableSource; import com.alibaba.druid.sql.ast.statement.SQLJoinTableSource.JoinType; @@ -1062,4 +1063,11 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter { x.getTableName().accept(this); return false; } + + @Override + public boolean visit(SQLSavePointStatement x) { + print("SAVEPOINT "); + x.getName().accept(this); + return false; + } } diff --git a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTVisitor.java b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTVisitor.java index 1f2b3814b8..db8ad39f2e 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTVisitor.java @@ -66,6 +66,7 @@ import com.alibaba.druid.sql.ast.statement.SQLDropViewStatement; import com.alibaba.druid.sql.ast.statement.SQLExprTableSource; import com.alibaba.druid.sql.ast.statement.SQLInsertStatement; import com.alibaba.druid.sql.ast.statement.SQLJoinTableSource; +import com.alibaba.druid.sql.ast.statement.SQLSavePointStatement; import com.alibaba.druid.sql.ast.statement.SQLSelect; import com.alibaba.druid.sql.ast.statement.SQLSelectGroupByClause; import com.alibaba.druid.sql.ast.statement.SQLSelectItem; @@ -355,4 +356,8 @@ public interface SQLASTVisitor { boolean visit(SQLDropViewStatement x); void endVisit(SQLDropViewStatement x); + + boolean visit(SQLSavePointStatement x); + + void endVisit(SQLSavePointStatement x); } diff --git a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTVisitorAdapter.java b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTVisitorAdapter.java index 35ef0fe360..a647e6bbc4 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTVisitorAdapter.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTVisitorAdapter.java @@ -67,6 +67,7 @@ import com.alibaba.druid.sql.ast.statement.SQLInsertStatement; import com.alibaba.druid.sql.ast.statement.SQLInsertStatement.ValuesClause; import com.alibaba.druid.sql.ast.statement.SQLAlterTableAddColumn; import com.alibaba.druid.sql.ast.statement.SQLJoinTableSource; +import com.alibaba.druid.sql.ast.statement.SQLSavePointStatement; import com.alibaba.druid.sql.ast.statement.SQLSelect; import com.alibaba.druid.sql.ast.statement.SQLSelectGroupByClause; import com.alibaba.druid.sql.ast.statement.SQLSelectItem; @@ -628,4 +629,14 @@ public class SQLASTVisitorAdapter implements SQLASTVisitor { public void endVisit(SQLDropViewStatement x) { } + + @Override + public boolean visit(SQLSavePointStatement x) { + return true; + } + + @Override + public void endVisit(SQLSavePointStatement x) { + + } }