improve sql parser

This commit is contained in:
wenshao
2013-08-04 14:12:37 +08:00
parent 4d8548ba8b
commit 0c2ddd77e9
28 changed files with 1126 additions and 29 deletions
@@ -20,7 +20,6 @@ import java.util.List;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLStatementImpl;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
public class SQLGrantStatement extends SQLStatementImpl {
@@ -31,11 +30,14 @@ public class SQLGrantStatement extends SQLStatementImpl {
private SQLExpr to;
// mysql
private ObjectType objectType;
private SQLExpr maxQueriesPerHour;
private SQLExpr maxUpdatesPerHour;
private SQLExpr maxConnectionsPerHour;
private SQLExpr maxUserConnections;
private boolean adminOption;
@Override
protected void accept0(SQLASTVisitor visitor) {
if (visitor.visit(this)) {
@@ -45,6 +47,14 @@ public class SQLGrantStatement extends SQLStatementImpl {
visitor.endVisit(this);
}
public ObjectType getObjectType() {
return objectType;
}
public void setObjectType(ObjectType objectType) {
this.objectType = objectType;
}
public SQLExpr getOn() {
return on;
}
@@ -65,12 +75,6 @@ public class SQLGrantStatement extends SQLStatementImpl {
return privileges;
}
public void addPrivileges(String privilege) {
SQLIdentifierExpr expr = new SQLIdentifierExpr(privilege);
expr.setParent(this);
this.privileges.add(expr);
}
public SQLExpr getMaxQueriesPerHour() {
return maxQueriesPerHour;
}
@@ -103,4 +107,15 @@ public class SQLGrantStatement extends SQLStatementImpl {
this.maxUserConnections = maxUserConnections;
}
public boolean isAdminOption() {
return adminOption;
}
public void setAdminOption(boolean adminOption) {
this.adminOption = adminOption;
}
public static enum ObjectType {
TABLE, FUNCTION, PROCEDURE, USER
}
}
@@ -0,0 +1,58 @@
/*
* 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.ast.statement;
import java.util.ArrayList;
import java.util.List;
import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlASTVisitor;
public class MySqlOptimizeStatement extends MySqlStatementImpl {
private boolean noWriteToBinlog = false;
private boolean local = false;
protected final List<SQLExprTableSource> tableSources = new ArrayList<SQLExprTableSource>();
public void accept0(MySqlASTVisitor visitor) {
if (visitor.visit(this)) {
acceptChild(visitor, tableSources);
}
visitor.endVisit(this);
}
public boolean isNoWriteToBinlog() {
return noWriteToBinlog;
}
public void setNoWriteToBinlog(boolean noWriteToBinlog) {
this.noWriteToBinlog = noWriteToBinlog;
}
public boolean isLocal() {
return local;
}
public void setLocal(boolean local) {
this.local = local;
}
public List<SQLExprTableSource> getTableSources() {
return tableSources;
}
}
@@ -50,6 +50,7 @@ public class MySqlLexer extends Lexer {
map.put("SHOW", Token.SHOW);
map.put("CACHE", Token.CACHE);
map.put("ANALYZE", Token.ANALYZE);
map.put("OPTIMIZE", Token.OPTIMIZE);
DEFAULT_MYSQL_KEYWORDS = new Keywords(map);
}
@@ -196,7 +196,7 @@ public class MySqlSelectParser extends SQLSelectParser {
queryBlock.setLimit(parseLimit());
}
if (identifierEquals("PROCEDURE")) {
if (lexer.token() == Token.PROCEDURE) {
lexer.nextToken();
throw new ParserException("TODO");
}
@@ -85,6 +85,7 @@ import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlLoadDataInFileStat
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.MySqlOptimizeStatement;
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;
@@ -506,6 +507,20 @@ public class MySqlStatementParser extends SQLStatementParser {
}
return stmt;
}
public MySqlOptimizeStatement parseOptimize() {
accept(Token.OPTIMIZE);
accept(Token.TABLE);
MySqlOptimizeStatement stmt = new MySqlOptimizeStatement();
List<SQLName> names = new ArrayList<SQLName>();
this.exprParser.names(names, stmt);
for (SQLName name : names) {
stmt.getTableSources().add(new SQLExprTableSource(name));
}
return stmt;
}
public SQLStatement parseReset() {
acceptIdentifier(RESET);
@@ -594,6 +609,12 @@ public class MySqlStatementParser extends SQLStatementParser {
statementList.add(stmt);
return true;
}
if (lexer.token() == Token.OPTIMIZE) {
SQLStatement stmt = parseOptimize();
statementList.add(stmt);
return true;
}
if (identifierEquals("HELP")) {
lexer.nextToken();
@@ -910,7 +931,7 @@ public class MySqlStatementParser extends SQLStatementParser {
return stmt;
}
if (identifierEquals("FUNCTION")) {
if (lexer.token() == Token.FUNCTION) {
lexer.nextToken();
MySqlShowCreateFunctionStatement stmt = new MySqlShowCreateFunctionStatement();
@@ -918,7 +939,7 @@ public class MySqlStatementParser extends SQLStatementParser {
return stmt;
}
if (identifierEquals("PROCEDURE")) {
if (lexer.token() == Token.PROCEDURE) {
lexer.nextToken();
MySqlShowCreateProcedureStatement stmt = new MySqlShowCreateProcedureStatement();
@@ -997,7 +1018,7 @@ public class MySqlStatementParser extends SQLStatementParser {
return stmt;
}
if (identifierEquals("FUNCTION")) {
if (lexer.token() == Token.FUNCTION) {
lexer.nextToken();
if (identifierEquals("CODE")) {
@@ -1131,7 +1152,7 @@ public class MySqlStatementParser extends SQLStatementParser {
return stmt;
}
if (identifierEquals("PROCEDURE")) {
if (lexer.token() == Token.PROCEDURE) {
lexer.nextToken();
if (identifierEquals("CODE")) {
@@ -2342,7 +2363,7 @@ public class MySqlStatementParser extends SQLStatementParser {
throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal());
} else if (identifierEquals("CHECK")) {
throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal());
} else if (identifierEquals("OPTIMIZE")) {
} else if (lexer.token() == Token.OPTIMIZE) {
throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal());
} else if (identifierEquals("REBUILD")) {
throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal());
@@ -56,6 +56,7 @@ 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.MySqlOptimizeStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlPartitionByHash;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlPartitionByKey;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlPartitionByList;
@@ -562,4 +563,8 @@ public interface MySqlASTVisitor extends SQLASTVisitor {
boolean visit(MySqlAlterUserStatement x);
void endVisit(MySqlAlterUserStatement x);
boolean visit(MySqlOptimizeStatement x);
void endVisit(MySqlOptimizeStatement x);
} //
@@ -58,6 +58,7 @@ 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.MySqlOptimizeStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlPartitionByHash;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlPartitionByKey;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlPartitionByList;
@@ -1247,4 +1248,14 @@ public class MySqlASTVisitorAdapter extends SQLASTVisitorAdapter implements MySq
public void endVisit(MySqlAlterUserStatement x) {
}
@Override
public boolean visit(MySqlOptimizeStatement x) {
return true;
}
@Override
public void endVisit(MySqlOptimizeStatement x) {
}
} //
@@ -80,6 +80,7 @@ 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.MySqlOptimizeStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlPartitionByHash;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlPartitionByKey;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlPartitionByList;
@@ -3022,6 +3023,28 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV
}
@Override
public boolean visit(MySqlOptimizeStatement x) {
print("OPTIMIZE ");
if (x.isNoWriteToBinlog()) {
print("NO_WRITE_TO_BINLOG ");
}
if (x.isLocal()) {
print("LOCAL ");
}
print("TABLE ");
printAndAccept(x.getTableSources(), ", ");
return false;
}
@Override
public void endVisit(MySqlOptimizeStatement x) {
}
@Override
public boolean visit(MySqlAlterUserStatement x) {
print("ALTER USER");
@@ -71,6 +71,7 @@ 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.MySqlOptimizeStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlPartitionByHash;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlPartitionByKey;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlPartitionByList;
@@ -1330,5 +1331,15 @@ public class MySqlSchemaStatVisitor extends SchemaStatVisitor implements MySqlAS
public void endVisit(MySqlAlterUserStatement x) {
}
@Override
public boolean visit(MySqlOptimizeStatement x) {
return true;
}
@Override
public void endVisit(MySqlOptimizeStatement x) {
}
}
@@ -63,7 +63,6 @@ public class OracleLexer extends Lexer {
map.put("OF", Token.OF);
map.put("PRIOR", Token.PRIOR);
map.put("PROCEDURE", Token.PROCEDURE);
map.put("REJECT", Token.REJECT);
map.put("RETURNING", Token.RETURNING);
map.put("SAVEPOINT", Token.SAVEPOINT);
@@ -52,6 +52,8 @@ public class Keywords {
map.put("DEFAULT", Token.DEFAULT);
map.put("COLUMN", Token.COLUMN);
map.put("TABLESPACE", Token.TABLESPACE);
map.put("PROCEDURE", Token.PROCEDURE);
map.put("FUNCTION", Token.FUNCTION);
map.put("DELETE", Token.DELETE);
map.put("DESC", Token.DESC);
@@ -102,6 +102,7 @@ public class SQLParser {
case SEQUENCE:
case USER:
case ANALYZE:
case OPTIMIZE:
case GRANT:
alias = lexer.stringVal();
lexer.nextToken();
@@ -21,6 +21,7 @@ import java.util.List;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLName;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.expr.SQLListExpr;
import com.alibaba.druid.sql.ast.expr.SQLQueryExpr;
import com.alibaba.druid.sql.ast.statement.SQLAlterTableAddColumn;
@@ -51,6 +52,7 @@ import com.alibaba.druid.sql.ast.statement.SQLDropViewStatement;
import com.alibaba.druid.sql.ast.statement.SQLExplainStatement;
import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
import com.alibaba.druid.sql.ast.statement.SQLGrantStatement;
import com.alibaba.druid.sql.ast.statement.SQLGrantStatement.ObjectType;
import com.alibaba.druid.sql.ast.statement.SQLInsertInto;
import com.alibaba.druid.sql.ast.statement.SQLInsertStatement;
import com.alibaba.druid.sql.ast.statement.SQLPrimaryKey;
@@ -318,41 +320,141 @@ public class SQLStatementParser extends SQLParser {
SQLGrantStatement stmt = new SQLGrantStatement();
for (;;) {
String privilege = null;
if (lexer.token() == Token.ALL) {
lexer.nextToken();
if (identifierEquals("PRIVILEGES")) {
lexer.nextToken();
stmt.addPrivileges("ALL PRIVILEGES");
privilege = "ALL PRIVILEGES";
} else {
stmt.addPrivileges("ALL");
privilege = "ALL";
}
} else if (lexer.token() == Token.SELECT) {
stmt.addPrivileges("SELECT");
privilege = "SELECT";
lexer.nextToken();
} else if (lexer.token() == Token.UPDATE) {
stmt.addPrivileges("UPDATE");
privilege = "UPDATE";
lexer.nextToken();
} else if (lexer.token() == Token.DELETE) {
stmt.addPrivileges("DELETE");
privilege = "DELETE";
lexer.nextToken();
} else if (lexer.token() == Token.INSERT) {
stmt.addPrivileges("INSERT");
privilege = "INSERT";
lexer.nextToken();
} else if (lexer.token() == Token.REFERENCES) {
privilege = "REFERENCES";
lexer.nextToken();
} else if (lexer.token() == Token.CREATE) {
lexer.nextToken();
if (lexer.token() == Token.TABLE) {
stmt.addPrivileges("CREATE TABLE");
privilege = "CREATE TABLE";
lexer.nextToken();
} else if (lexer.token() == Token.SESSION) {
privilege = "CREATE SESSION";
lexer.nextToken();
} else if (lexer.token() == Token.ANY) {
lexer.nextToken();
if (lexer.token() == Token.TABLE) {
lexer.nextToken();
privilege = "CREATE ANY TABLE";
} else if (identifierEquals("MATERIALIZED")) {
lexer.nextToken();
accept(Token.VIEW);
privilege = "CREATE ANY MATERIALIZED VIEW";
} else {
throw new ParserException("TODO : " + lexer.token() + " " + lexer.stringVal());
}
} else if (identifierEquals("SYNONYM")) {
stmt.addPrivileges("CREATE SYNONYM");
privilege = "CREATE SYNONYM";
lexer.nextToken();
} else if (identifierEquals("ROUTINE")) {
privilege = "CREATE ROUTINE";
lexer.nextToken();
} else {
throw new ParserException("TODO : " + lexer.token() + " " + lexer.stringVal());
}
} else if (identifierEquals("USAGE")) {
stmt.addPrivileges("USAGE");
} else if (lexer.token() == Token.ALTER) {
lexer.nextToken();
if (lexer.token() == Token.TABLE) {
privilege = "ALTER TABLE";
lexer.nextToken();
} else if (lexer.token() == Token.SESSION) {
privilege = "ALTER SESSION";
lexer.nextToken();
} else if (lexer.token() == Token.ANY) {
lexer.nextToken();
if (lexer.token() == Token.TABLE) {
lexer.nextToken();
privilege = "ALTER ANY TABLE";
} else if (identifierEquals("MATERIALIZED")) {
lexer.nextToken();
accept(Token.VIEW);
privilege = "ALTER ANY MATERIALIZED VIEW";
} else {
throw new ParserException("TODO : " + lexer.token() + " " + lexer.stringVal());
}
} else {
throw new ParserException("TODO : " + lexer.token() + " " + lexer.stringVal());
}
} else if (lexer.token() == Token.DROP) {
lexer.nextToken();
if (lexer.token() == Token.DROP) {
privilege = "DROP TABLE";
lexer.nextToken();
} else if (lexer.token() == Token.SESSION) {
privilege = "DROP SESSION";
lexer.nextToken();
} else if (lexer.token() == Token.ANY) {
lexer.nextToken();
if (lexer.token() == Token.TABLE) {
lexer.nextToken();
privilege = "DROP ANY TABLE";
} else if (identifierEquals("MATERIALIZED")) {
lexer.nextToken();
accept(Token.VIEW);
privilege = "DROP ANY MATERIALIZED VIEW";
} else {
throw new ParserException("TODO : " + lexer.token() + " " + lexer.stringVal());
}
} else {
throw new ParserException("TODO : " + lexer.token() + " " + lexer.stringVal());
}
} else if (identifierEquals("USAGE")) {
privilege = "USAGE";
lexer.nextToken();
} else if (identifierEquals("EXECUTE")) {
privilege = "EXECUTE";
lexer.nextToken();
} else if (identifierEquals("PROXY")) {
privilege = "PROXY";
lexer.nextToken();
} else if (identifierEquals("QUERY")) {
lexer.nextToken();
acceptIdentifier("REWRITE");
privilege = "QUERY REWRITE";
} else if (identifierEquals("GLOBAL")) {
lexer.nextToken();
acceptIdentifier("QUERY");
acceptIdentifier("REWRITE");
privilege = "GLOBAL QUERY REWRITE";
} else if (identifierEquals("INHERIT")) {
lexer.nextToken();
acceptIdentifier("PRIVILEGES");
privilege = "INHERIT PRIVILEGES";
}
if (privilege != null) {
SQLExpr expr = new SQLIdentifierExpr(privilege);
if (lexer.token() == Token.LPAREN) {
expr = this.exprParser.primaryRest(expr);
}
expr.setParent(stmt);
stmt.getPrivileges().add(expr);
}
if (lexer.token() == Token.COMMA) {
@@ -364,6 +466,21 @@ public class SQLStatementParser extends SQLParser {
if (lexer.token() == Token.ON) {
lexer.nextToken();
if (lexer.token() == Token.PROCEDURE) {
lexer.nextToken();
stmt.setObjectType(ObjectType.PROCEDURE);
} else if (lexer.token() == Token.FUNCTION) {
lexer.nextToken();
stmt.setObjectType(ObjectType.FUNCTION);
} else if (lexer.token() == Token.TABLE) {
lexer.nextToken();
stmt.setObjectType(ObjectType.TABLE);
} else if (lexer.token() == Token.USER) {
lexer.nextToken();
stmt.setObjectType(ObjectType.USER);
}
stmt.setOn(this.exprParser.expr());
}
@@ -381,28 +498,34 @@ public class SQLStatementParser extends SQLParser {
stmt.setMaxQueriesPerHour(this.exprParser.primary());
continue;
}
if (identifierEquals("MAX_UPDATES_PER_HOUR")) {
lexer.nextToken();
stmt.setMaxUpdatesPerHour(this.exprParser.primary());
continue;
}
if (identifierEquals("MAX_CONNECTIONS_PER_HOUR")) {
lexer.nextToken();
stmt.setMaxConnectionsPerHour(this.exprParser.primary());
continue;
}
if (identifierEquals("MAX_USER_CONNECTIONS")) {
lexer.nextToken();
stmt.setMaxUserConnections(this.exprParser.primary());
continue;
}
break;
}
}
if (identifierEquals("ADMIN")) {
lexer.nextToken();
acceptIdentifier("OPTION");
stmt.setAdminOption(true);
}
return stmt;
}
@@ -162,6 +162,7 @@ public enum Token {
ADVISE("ADVISE"),
SESSION("SESSION"),
PROCEDURE("PROCEDURE"),
FUNCTION("FUNCTION"),
SYSDATE("SYSDATE"),
DECLARE("DECLARE"),
EXCEPTION("EXCEPTION"),
@@ -204,6 +205,7 @@ public enum Token {
COMPUTE("COMPUTE"),
ANALYZE("ANALYZE"),
OPTIMIZE("OPTIMIZE"),
// transact-sql
TOP("TOP"),
@@ -1723,6 +1723,12 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Printab
if (x.getOn() != null) {
print(" ON ");
if (x.getObjectType() != null) {
print(x.getObjectType().name());
print(' ');
}
x.getOn().accept(this);
}
@@ -1767,6 +1773,14 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Printab
print(" MAX_USER_CONNECTIONS ");
x.getMaxUserConnections().accept(this);
}
if (x.isAdminOption()) {
if (!with) {
print(" WITH");
with = true;
}
print(" ADMIN OPTION");
}
return false;
}