From 3680b3fbab71f53d553737f606d67b8ee21d2a68 Mon Sep 17 00:00:00 2001 From: wenshao Date: Sun, 11 Mar 2018 15:58:34 +0800 Subject: [PATCH] improved mysql parser, bug fixed for mysql grant syntax support. for issue #2338 --- .../dialect/mysql/ast/expr/MySqlUserName.java | 14 ++- .../dialect/mysql/parser/MySqlExprParser.java | 16 ++++ .../mysql/visitor/MySqlOutputVisitor.java | 13 ++- .../druid/sql/parser/SQLStatementParser.java | 12 ++- .../java/com/alibaba/druid/util/FnvHash.java | 1 + .../sql/mysql/grant/MySqlGrantTest_35.java | 93 +++++++++++++++++-- 6 files changed, 134 insertions(+), 15 deletions(-) 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 index a57677c868..70a541549e 100644 --- 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 @@ -27,6 +27,7 @@ public class MySqlUserName extends MySqlExprImpl implements SQLName, Cloneable { private String userName; private String host; + private String identifiedBy; private long userNameHashCod64; private long hashCode64; @@ -63,6 +64,14 @@ public class MySqlUserName extends MySqlExprImpl implements SQLName, Cloneable { return userName + '@' + host; } + public String getIdentifiedBy() { + return identifiedBy; + } + + public void setIdentifiedBy(String identifiedBy) { + this.identifiedBy = identifiedBy; + } + public String toString() { return getSimpleName(); } @@ -70,8 +79,9 @@ public class MySqlUserName extends MySqlExprImpl implements SQLName, Cloneable { public MySqlUserName clone() { MySqlUserName x = new MySqlUserName(); - x.userName = userName; - x.host = host; + x.userName = userName; + x.host = host; + x.identifiedBy = identifiedBy; return x; } 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 a0a7c8e9ee..2b51601605 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 @@ -348,6 +348,14 @@ public class MySqlExprParser extends SQLExprParser { userName.setHost(lexer.stringVal()); } lexer.nextToken(); + + if (lexer.token() == Token.IDENTIFIED) { + lexer.nextToken(); + accept(Token.BY); + userName.setIdentifiedBy(lexer.stringVal()); + lexer.nextToken(); + } + return userName; } @@ -696,6 +704,14 @@ public class MySqlExprParser extends SQLExprParser { userName.setHost(lexer.stringVal()); } lexer.nextToken(); + + if (lexer.token() == Token.IDENTIFIED) { + lexer.nextToken(); + accept(Token.BY); + userName.setIdentifiedBy(lexer.stringVal()); + lexer.nextToken(); + } + return userName; } return super.nameRest(name); 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 67ea3a9d4a..ef26b1e57f 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 @@ -2047,10 +2047,19 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV @Override public boolean visit(MySqlUserName x) { print0(x.getUserName()); - if (x.getHost() != null) { + + String host = x.getHost(); + if (host != null) { print('@'); - print0(x.getHost()); + print0(host); } + + String identifiedBy = x.getIdentifiedBy(); + if (identifiedBy != null) { + print0(ucase ? " IDENTIFIED BY " : " identified by "); + print0(identifiedBy); + } + return false; } 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 8333f2c496..7849b9fce2 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/SQLStatementParser.java +++ b/src/main/java/com/alibaba/druid/sql/parser/SQLStatementParser.java @@ -693,7 +693,7 @@ public class SQLStatementParser extends SQLParser { } else { expr = this.exprParser.expr(); } - + if (stmt.getObjectType() == SQLObjectType.TABLE || stmt.getObjectType() == null) { stmt.setOn(new SQLExprTableSource(expr)); } else { @@ -709,6 +709,11 @@ public class SQLStatementParser extends SQLParser { if (lexer.token == Token.WITH) { lexer.nextToken(); + if (lexer.token == Token.GRANT) { + lexer.nextToken(); + acceptIdentifier("OPTION"); + } + for (;;) { if (lexer.identifierEquals("MAX_QUERIES_PER_HOUR")) { lexer.nextToken(); @@ -862,6 +867,9 @@ public class SQLStatementParser extends SQLParser { } else if (lexer.token == Token.SESSION) { privilege = "ALTER SESSION"; lexer.nextToken(); + } else if (lexer.identifierEquals(FnvHash.Constants.ROUTINE)) { + privilege = "ALTER ROUTINE"; + lexer.nextToken(); } else if (lexer.token == Token.ANY) { lexer.nextToken(); @@ -875,6 +883,8 @@ public class SQLStatementParser extends SQLParser { } else { throw new ParserException("TODO : " + lexer.token + " " + lexer.stringVal()); } + } else if (lexer.token == Token.ON) { + privilege = "ALTER"; } else { throw new ParserException("TODO : " + lexer.token + " " + lexer.stringVal()); } diff --git a/src/main/java/com/alibaba/druid/util/FnvHash.java b/src/main/java/com/alibaba/druid/util/FnvHash.java index 6348f69437..965b162c17 100644 --- a/src/main/java/com/alibaba/druid/util/FnvHash.java +++ b/src/main/java/com/alibaba/druid/util/FnvHash.java @@ -639,5 +639,6 @@ public final class FnvHash { long COMPRESSION = fnv1a_64_lower("COMPRESSION"); long KEY_BLOCK_SIZE = fnv1a_64_lower("KEY_BLOCK_SIZE"); long CHECKSUM = fnv1a_64_lower("CHECKSUM"); + long ROUTINE = fnv1a_64_lower("ROUTINE"); } } diff --git a/src/test/java/com/alibaba/druid/bvt/sql/mysql/grant/MySqlGrantTest_35.java b/src/test/java/com/alibaba/druid/bvt/sql/mysql/grant/MySqlGrantTest_35.java index 23b7b5c517..86d34ea8d6 100644 --- a/src/test/java/com/alibaba/druid/bvt/sql/mysql/grant/MySqlGrantTest_35.java +++ b/src/test/java/com/alibaba/druid/bvt/sql/mysql/grant/MySqlGrantTest_35.java @@ -31,7 +31,6 @@ public class MySqlGrantTest_35 extends MysqlTest { MySqlStatementParser parser = new MySqlStatementParser(sql); List statementList = parser.parseStatementList(); SQLStatement stmt = statementList.get(0); -// print(statementList); assertEquals(1, statementList.size()); @@ -42,18 +41,92 @@ public class MySqlGrantTest_35 extends MysqlTest { assertEquals("GRANT CREATE ON * TO hello@'%';", // output); -// System.out.println("Tables : " + visitor.getTables()); -// System.out.println("fields : " + visitor.getColumns()); -// System.out.println("coditions : " + visitor.getConditions()); -// System.out.println("orderBy : " + visitor.getOrderByColumns()); - assertEquals(0, visitor.getTables().size()); assertEquals(0, visitor.getColumns().size()); assertEquals(0, visitor.getConditions().size()); + } -// assertTrue(visitor.getTables().containsKey(new TableStat.Name("City"))); -// assertTrue(visitor.getTables().containsKey(new TableStat.Name("t2"))); - -// assertTrue(visitor.getColumns().contains(new Column("t2", "id"))); + public void test_1() throws Exception { + String sql = "GRANT ALTER ON . TO hello@'%'; "; + + MySqlStatementParser parser = new MySqlStatementParser(sql); + List statementList = parser.parseStatementList(); + SQLStatement stmt = statementList.get(0); + + assertEquals(1, statementList.size()); + + MySqlSchemaStatVisitor visitor = new MySqlSchemaStatVisitor(); + stmt.accept(visitor); + + String output = SQLUtils.toMySqlString(stmt); + assertEquals("GRANT ALTER ON * TO hello@'%';", // + output); + + assertEquals(0, visitor.getTables().size()); + assertEquals(0, visitor.getColumns().size()); + assertEquals(0, visitor.getConditions().size()); + } + + public void test_2() throws Exception { + String sql = "GRANT CREATE TEMPORARY TABLE ON . TO hello@'%';"; + + MySqlStatementParser parser = new MySqlStatementParser(sql); + List statementList = parser.parseStatementList(); + SQLStatement stmt = statementList.get(0); + + assertEquals(1, statementList.size()); + + MySqlSchemaStatVisitor visitor = new MySqlSchemaStatVisitor(); + stmt.accept(visitor); + + String output = SQLUtils.toMySqlString(stmt); + assertEquals("GRANT CREATE TEMPORARY TABLE ON * TO hello@'%';", // + output); + + assertEquals(0, visitor.getTables().size()); + assertEquals(0, visitor.getColumns().size()); + assertEquals(0, visitor.getConditions().size()); + } + + public void test_3() throws Exception { + String sql = "GRANT ALTER ROUTINE ON . TO hello@'%';"; + + MySqlStatementParser parser = new MySqlStatementParser(sql); + List statementList = parser.parseStatementList(); + SQLStatement stmt = statementList.get(0); + + assertEquals(1, statementList.size()); + + MySqlSchemaStatVisitor visitor = new MySqlSchemaStatVisitor(); + stmt.accept(visitor); + + String output = SQLUtils.toMySqlString(stmt); + assertEquals("GRANT ALTER ROUTINE ON * TO hello@'%';", // + output); + + assertEquals(0, visitor.getTables().size()); + assertEquals(0, visitor.getColumns().size()); + assertEquals(0, visitor.getConditions().size()); + } + + public void test_4() throws Exception { + String sql = "grant all on . to hello@'%' identified by 'helloPassword' with grant option MAX_QUERIES_PER_HOUR 90;"; + + MySqlStatementParser parser = new MySqlStatementParser(sql); + List statementList = parser.parseStatementList(); + SQLStatement stmt = statementList.get(0); + + assertEquals(1, statementList.size()); + + MySqlSchemaStatVisitor visitor = new MySqlSchemaStatVisitor(); + stmt.accept(visitor); + + String output = SQLUtils.toMySqlString(stmt); + assertEquals("GRANT ALL ON * TO hello@'%' IDENTIFIED BY helloPassword WITH MAX_QUERIES_PER_HOUR 90;", // + output); + + assertEquals(0, visitor.getTables().size()); + assertEquals(0, visitor.getColumns().size()); + assertEquals(0, visitor.getConditions().size()); } }