diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/expr/MySqlUserName.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/expr/MySqlUserName.java new file mode 100644 index 0000000000..287627b4d3 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/ast/expr/MySqlUserName.java @@ -0,0 +1,41 @@ +package com.alibaba.druid.sql.dialect.mysql.ast.expr; + +import com.alibaba.druid.sql.ast.SQLName; +import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlASTVisitor; + +public class MySqlUserName extends MySqlExprImpl implements SQLName { + + private static final long serialVersionUID = 1L; + private String userName; + private String host; + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getHost() { + return host; + } + + public void setHost(String host) { + this.host = host; + } + + @Override + public void accept0(MySqlASTVisitor visitor) { + visitor.visit(this); + visitor.endVisit(this); + } + + public String getSimleName() { + return userName + '@' + host; + } + + public String toString() { + return getSimleName(); + } +} diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlExprParser.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlExprParser.java index 8bfc891b93..be0be9a46b 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlExprParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlExprParser.java @@ -16,6 +16,7 @@ package com.alibaba.druid.sql.dialect.mysql.parser; import com.alibaba.druid.sql.ast.SQLExpr; +import com.alibaba.druid.sql.ast.SQLName; import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr; import com.alibaba.druid.sql.ast.expr.SQLBinaryOperator; import com.alibaba.druid.sql.ast.expr.SQLCharExpr; @@ -35,6 +36,7 @@ import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlIntervalUnit; import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlMatchAgainstExpr; import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlMatchAgainstExpr.SearchModifier; import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlOutFileExpr; +import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlUserName; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSQLColumnDefinition; import com.alibaba.druid.sql.parser.Lexer; import com.alibaba.druid.sql.parser.ParserException; @@ -427,6 +429,24 @@ public class MySqlExprParser extends SQLExprParser { return primaryRest(expr); } } + + if (lexer.token() == Token.VARIANT && "@".equals(lexer.stringVal())) { + lexer.nextToken(); + MySqlUserName userName = new MySqlUserName(); + if (expr instanceof SQLCharExpr) { + userName.setUserName(((SQLCharExpr)expr).toString()); + } else { + userName.setUserName(((SQLIdentifierExpr)expr).getName()); + } + + if (lexer.token() == Token.LITERAL_CHARS) { + userName.setHost("'" + lexer.stringVal() + "'"); + } else { + userName.setHost(lexer.stringVal()); + } + lexer.nextToken(); + return userName; + } return super.primaryRest(expr); } @@ -543,4 +563,21 @@ public class MySqlExprParser extends SQLExprParser { return item; } + + public SQLName nameRest(SQLName name) throws ParserException { + if (lexer.token() == Token.VARIANT && "@".equals(lexer.stringVal())) { + lexer.nextToken(); + MySqlUserName userName = new MySqlUserName(); + userName.setUserName(((SQLIdentifierExpr)name).getName()); + + if (lexer.token() == Token.LITERAL_CHARS) { + userName.setHost("'" + lexer.stringVal() + "'"); + } else { + userName.setHost(lexer.stringVal()); + } + lexer.nextToken(); + return userName; + } + return super.nameRest(name); + } } 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 1c2af478a3..b7e0b7dc98 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 @@ -748,7 +748,7 @@ public class MySqlStatementParser extends SQLStatementParser { if (lexer.token() == Token.FOR) { lexer.nextToken(); - stmt.setUser(this.exprParser.name()); + stmt.setUser(this.exprParser.expr()); } return stmt; 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 a2e6b96ee7..5f85d59180 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 @@ -23,6 +23,7 @@ import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlExtractExpr; import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlIntervalExpr; import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlMatchAgainstExpr; import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlOutFileExpr; +import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlUserName; import com.alibaba.druid.sql.dialect.mysql.ast.statement.CobarShowStatus; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlBinlogStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCommitStatement; @@ -326,4 +327,8 @@ public interface MySqlASTVisitor extends SQLASTVisitor { boolean visit(MySqlShowGrantsStatement x); void endVisit(MySqlShowGrantsStatement x); + + boolean visit(MySqlUserName x); + + void endVisit(MySqlUserName 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 099dd9801d..5c21645b3b 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 @@ -8,6 +8,7 @@ import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlExtractExpr; import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlIntervalExpr; import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlMatchAgainstExpr; import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlOutFileExpr; +import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlUserName; import com.alibaba.druid.sql.dialect.mysql.ast.statement.CobarShowStatus; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlBinlogStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCommitStatement; @@ -706,4 +707,14 @@ public class MySqlASTVisitorAdapter extends SQLASTVisitorAdapter implements @Override public void endVisit(MySqlShowGrantsStatement x) { } + + @Override + public boolean visit(MySqlUserName x) { + return true; + } + + @Override + public void endVisit(MySqlUserName 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 cb3293fd75..c8d8fdf52f 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 @@ -38,6 +38,7 @@ import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlExtractExpr; import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlIntervalExpr; import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlMatchAgainstExpr; import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlOutFileExpr; +import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlUserName; import com.alibaba.druid.sql.dialect.mysql.ast.statement.CobarShowStatus; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlBinlogStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCommitStatement; @@ -1794,6 +1795,11 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV @Override public boolean visit(MySqlShowGrantsStatement x) { + print("SHOW GRANTS"); + if (x.getUser() != null) { + print(" FOR "); + x.getUser().accept(this); + } return false; } @@ -1801,4 +1807,19 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV public void endVisit(MySqlShowGrantsStatement x) { } + + @Override + public boolean visit(MySqlUserName x) { + print(x.getUserName()); + if (x.getHost() != null) { + print('@'); + print(x.getHost()); + } + return false; + } + + @Override + public void endVisit(MySqlUserName 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 3a2c5c9fe5..c6188767f2 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 @@ -17,6 +17,7 @@ import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlExtractExpr; import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlIntervalExpr; import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlMatchAgainstExpr; import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlOutFileExpr; +import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlUserName; import com.alibaba.druid.sql.dialect.mysql.ast.statement.CobarShowStatus; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlBinlogStatement; import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCommitStatement; @@ -769,4 +770,14 @@ public class MySqlSchemaStatVisitor extends SchemaStatVisitor implements MySqlAS public void endVisit(MySqlShowGrantsStatement x) { } + + @Override + public boolean visit(MySqlUserName x) { + return false; + } + + @Override + public void endVisit(MySqlUserName x) { + + } } diff --git a/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java b/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java index 6bc50bcc42..6933ac8f53 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java +++ b/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java @@ -204,7 +204,7 @@ public class SQLExprParser extends SQLParser { } else if (varRefExpr.getName().equals("@@") && lexer.token() == Token.LITERAL_CHARS) { varRefExpr.setName("@@'" + lexer.stringVal() + "'"); lexer.nextToken(); - } + } sqlExpr = varRefExpr; break; case DEFAULT: @@ -612,6 +612,9 @@ public class SQLExprParser extends SQLParser { } else if (lexer.token() == Token.IDENTIFIER) { identName = lexer.stringVal(); + lexer.nextToken(); + } else if (lexer.token() == Token.LITERAL_CHARS) { + identName = '\'' + lexer.stringVal() + '\''; lexer.nextToken(); } else { throw new ParserException("error " + lexer.token()); @@ -1167,12 +1170,12 @@ public class SQLExprParser extends SQLParser { public SQLPrimaryKey parsePrimaryKey() { throw new ParserException("TODO"); } - + public SQLAssignItem parseAssignItem() { SQLAssignItem item = new SQLAssignItem(); - + SQLExpr var = primary(); - + if (var instanceof SQLIdentifierExpr) { var = new SQLVariantRefExpr(((SQLIdentifierExpr) var).getName()); } diff --git a/src/test/java/com/alibaba/druid/bvt/sql/cobar/DALParserTest.java b/src/test/java/com/alibaba/druid/bvt/sql/cobar/DALParserTest.java index 9e96cbbb1c..6f6fb2c923 100755 --- a/src/test/java/com/alibaba/druid/bvt/sql/cobar/DALParserTest.java +++ b/src/test/java/com/alibaba/druid/bvt/sql/cobar/DALParserTest.java @@ -613,25 +613,36 @@ public class DALParserTest extends TestCase { Assert.assertEquals("SHOW GRANTS FOR 'root'@'localhost'", output); } + public void test_show_grants_1() throws Exception { + String sql = "SHOW GRANTS"; + MySqlStatementParser parser = new MySqlStatementParser(sql); + MySqlShowGrantsStatement show = (MySqlShowGrantsStatement) parser.parseStatementList().get(0); + parser.match(Token.EOF); + String output = SQLUtils.toMySqlString(show); + Assert.assertEquals("SHOW GRANTS", output); + } + + public void test_show_grants_2() throws Exception { + String sql = "SHOW GRANTS FOR CURRENT_USER"; + MySqlStatementParser parser = new MySqlStatementParser(sql); + MySqlShowGrantsStatement show = (MySqlShowGrantsStatement) parser.parseStatementList().get(0); + parser.match(Token.EOF); + String output = SQLUtils.toMySqlString(show); + Assert.assertEquals("SHOW GRANTS FOR CURRENT_USER", output); + } + + public void test_show_grants_3() throws Exception { + String sql = "SHOW GRANTS FOR CURRENT_USER()"; + MySqlStatementParser parser = new MySqlStatementParser(sql); + MySqlShowGrantsStatement show = (MySqlShowGrantsStatement) parser.parseStatementList().get(0); + parser.match(Token.EOF); + String output = SQLUtils.toMySqlString(show); + Assert.assertEquals("SHOW GRANTS FOR CURRENT_USER()", output); + } + // // public void testShow() throws Exception { // -// sql = "SHOW grants for 'expr'"; -// lexer = new SQLLexer(sql); -// parser = new DALParser(lexer, new SQLExprParser(lexer)); -// show = (DALShowStatement) parser.show(); -// parser.match(Token.EOF); -// output = output2MySQL(show, sql); -// Assert.assertEquals("SHOW GRANTS FOR 'expr'", output); -// -// sql = "SHOW grants"; -// lexer = new SQLLexer(sql); -// parser = new DALParser(lexer, new SQLExprParser(lexer)); -// show = (DALShowStatement) parser.show(); -// parser.match(Token.EOF); -// output = output2MySQL(show, sql); -// Assert.assertEquals("SHOW GRANTS", output); -// // sql = "SHOW index from tb1 from db"; // lexer = new SQLLexer(sql); // parser = new DALParser(lexer, new SQLExprParser(lexer));