improve sql parser

This commit is contained in:
wenshao
2013-08-04 10:16:50 +08:00
parent 459901e8d9
commit c6d0165893
16 changed files with 244 additions and 46 deletions
@@ -0,0 +1,29 @@
package com.alibaba.druid.sql.ast.statement;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.SQLStatementImpl;
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
public class SQLExplainStatement extends SQLStatementImpl {
protected SQLStatement statement;
public SQLStatement getStatement() {
return statement;
}
public void setStatement(SQLStatement statement) {
if (statement != null) {
statement.setParent(this);
}
this.statement = statement;
}
@Override
protected void accept0(SQLASTVisitor visitor) {
if (visitor.visit(this)) {
acceptChild(visitor, statement);
}
visitor.endVisit(this);
}
}
@@ -35,7 +35,6 @@ import com.alibaba.druid.sql.ast.statement.SQLCharactorDataType;
import com.alibaba.druid.sql.ast.statement.SQLColumnConstraint;
import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition;
import com.alibaba.druid.sql.ast.statement.SQLCreateTableStatement;
import com.alibaba.druid.sql.ast.statement.SQLDropUserStatement;
import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock;
import com.alibaba.druid.sql.dialect.mysql.ast.MySqlForceIndexHint;
@@ -15,27 +15,36 @@
*/
package com.alibaba.druid.sql.dialect.oracle.ast.stmt;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.expr.SQLCharExpr;
import com.alibaba.druid.sql.ast.statement.SQLExplainStatement;
import com.alibaba.druid.sql.dialect.oracle.visitor.OracleASTVisitor;
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
public class OracleExplainStatement extends OracleStatementImpl {
public class OracleExplainStatement extends SQLExplainStatement implements OracleStatement {
private SQLCharExpr statementId;
private SQLExpr into;
private SQLStatement forStatement;
private SQLCharExpr statementId;
private SQLExpr into;
@Override
public void accept0(OracleASTVisitor visitor) {
if (visitor.visit(this)) {
acceptChild(visitor, statementId);
acceptChild(visitor, into);
acceptChild(visitor, forStatement);
acceptChild(visitor, statement);
}
visitor.endVisit(this);
}
protected void accept0(SQLASTVisitor visitor) {
accept0((OracleASTVisitor) visitor);
}
public String toString() {
return SQLUtils.toOracleString(this);
}
public SQLCharExpr getStatementId() {
return statementId;
}
@@ -52,12 +61,4 @@ public class OracleExplainStatement extends OracleStatementImpl {
this.into = into;
}
public SQLStatement getForStatement() {
return forStatement;
}
public void setForStatement(SQLStatement forStatement) {
this.forStatement = forStatement;
}
}
@@ -140,11 +140,6 @@ public class OracleStatementParser extends SQLStatementParser {
}
}
@Override
public void parseStatementList(List<SQLStatement> statementList) {
parseStatementList(statementList, -1);
}
public void parseStatementList(List<SQLStatement> statementList, int max) {
for (;;) {
if (max != -1) {
@@ -298,12 +293,12 @@ public class OracleStatementParser extends SQLStatementParser {
continue;
}
if (lexer.token() == Token.IDENTIFIER) {
if (identifierEquals("EXPLAIN")) {
statementList.add(this.parseExplain());
continue;
}
if (lexer.token() == Token.EXPLAIN) {
statementList.add(this.parseExplain());
continue;
}
if (lexer.token() == Token.IDENTIFIER) {
SQLExpr expr = exprParser.expr();
OracleExprStatement stmt = new OracleExprStatement(expr);
statementList.add(stmt);
@@ -470,7 +465,7 @@ public class OracleStatementParser extends SQLStatementParser {
statementList.add(stmt);
continue;
}
if (lexer.token() == Token.TRIGGER) {
SQLDropTriggerStatement stmt = parseDropTrigger(false);
statementList.add(stmt);
@@ -1453,16 +1448,8 @@ public class OracleStatementParser extends SQLStatementParser {
return clause;
}
public SQLStatement parseStatement() {
List<SQLStatement> list = new ArrayList<SQLStatement>();
this.parseStatementList(list, 1);
return list.get(0);
}
public OracleExplainStatement parseExplain() {
acceptIdentifier("EXPLAIN");
accept(Token.EXPLAIN);
acceptIdentifier("PLAN");
OracleExplainStatement stmt = new OracleExplainStatement();
@@ -1479,7 +1466,7 @@ public class OracleStatementParser extends SQLStatementParser {
}
accept(Token.FOR);
stmt.setForStatement(parseStatement());
stmt.setStatement(parseStatement());
return stmt;
}
@@ -1882,7 +1882,7 @@ public class OracleOutputVisitor extends SQLASTOutputVisitor implements OracleAS
print("FRO");
println();
x.getForStatement().accept(this);
x.getStatement().accept(this);
decrementIndent();
return false;
@@ -58,6 +58,7 @@ public class Keywords {
map.put("DISTINCT", Token.DISTINCT);
map.put("DROP", Token.DROP);
map.put("ELSE", Token.ELSE);
map.put("EXPLAIN", Token.EXPLAIN);
map.put("END", Token.END);
map.put("ESCAPE", Token.ESCAPE);
@@ -245,6 +245,7 @@ public class SQLExprParser extends SQLParser {
case INITIALLY:
case SEQUENCE:
case USER:
case EXPLAIN:
sqlExpr = new SQLIdentifierExpr(lexer.stringVal());
lexer.nextToken();
break;
@@ -48,6 +48,7 @@ import com.alibaba.druid.sql.ast.statement.SQLDropTableStatement;
import com.alibaba.druid.sql.ast.statement.SQLDropTriggerStatement;
import com.alibaba.druid.sql.ast.statement.SQLDropUserStatement;
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.SQLInsertInto;
import com.alibaba.druid.sql.ast.statement.SQLInsertStatement;
@@ -89,7 +90,17 @@ public class SQLStatementParser extends SQLParser {
}
public void parseStatementList(List<SQLStatement> statementList) {
parseStatementList(statementList, -1);
}
public void parseStatementList(List<SQLStatement> statementList, int max) {
for (;;) {
if (max != -1) {
if (statementList.size() >= max) {
return;
}
}
if (lexer.token() == Token.EOF) {
return;
}
@@ -125,6 +136,11 @@ public class SQLStatementParser extends SQLParser {
statementList.add(parseDeleteStatement());
continue;
}
if (lexer.token() == (Token.EXPLAIN)) {
statementList.add(parseExplain());
continue;
}
if (lexer.token() == Token.SET) {
statementList.add(parseSet());
@@ -587,7 +603,7 @@ public class SQLStatementParser extends SQLParser {
stmt.setCascade(Boolean.FALSE);
continue;
}
break;
}
@@ -1000,4 +1016,28 @@ public class SQLStatementParser extends SQLParser {
}
return item;
}
public SQLStatement parseStatement() {
List<SQLStatement> list = new ArrayList<SQLStatement>();
this.parseStatementList(list, 1);
return list.get(0);
}
public SQLExplainStatement parseExplain() {
accept(Token.EXPLAIN);
if (identifierEquals("PLAN")) {
lexer.nextToken();
}
if (lexer.token() == Token.FOR) {
lexer.nextToken();
}
SQLExplainStatement explain = new SQLExplainStatement();
explain.setStatement(parseStatement());
return explain;
}
}
@@ -22,6 +22,7 @@ package com.alibaba.druid.sql.parser;
* @formatter:off
*/
public enum Token {
EXPLAIN("EXPLAIN"),
FOR("FOR"),
IF("IF"),
INDEX("INDEX"),
@@ -101,6 +101,7 @@ import com.alibaba.druid.sql.ast.statement.SQLDropTableStatement;
import com.alibaba.druid.sql.ast.statement.SQLDropTriggerStatement;
import com.alibaba.druid.sql.ast.statement.SQLDropUserStatement;
import com.alibaba.druid.sql.ast.statement.SQLDropViewStatement;
import com.alibaba.druid.sql.ast.statement.SQLExplainStatement;
import com.alibaba.druid.sql.ast.statement.SQLExprHint;
import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
import com.alibaba.druid.sql.ast.statement.SQLForeignKeyConstraint;
@@ -1705,4 +1706,12 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter implements Printab
printAndAccept(x.getUsers(), ", ");
return false;
}
@Override
public boolean visit(SQLExplainStatement x) {
print("EXPLAIN");
println();
x.getStatement().accept(this);
return false;
}
}
@@ -85,6 +85,7 @@ import com.alibaba.druid.sql.ast.statement.SQLDropTableStatement;
import com.alibaba.druid.sql.ast.statement.SQLDropTriggerStatement;
import com.alibaba.druid.sql.ast.statement.SQLDropUserStatement;
import com.alibaba.druid.sql.ast.statement.SQLDropViewStatement;
import com.alibaba.druid.sql.ast.statement.SQLExplainStatement;
import com.alibaba.druid.sql.ast.statement.SQLExprHint;
import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
import com.alibaba.druid.sql.ast.statement.SQLForeignKeyImpl;
@@ -499,4 +500,8 @@ public interface SQLASTVisitor {
void endVisit(SQLDropUserStatement x);
boolean visit(SQLDropUserStatement x);
void endVisit(SQLExplainStatement x);
boolean visit(SQLExplainStatement x);
}
@@ -86,6 +86,7 @@ import com.alibaba.druid.sql.ast.statement.SQLDropTableStatement;
import com.alibaba.druid.sql.ast.statement.SQLDropTriggerStatement;
import com.alibaba.druid.sql.ast.statement.SQLDropUserStatement;
import com.alibaba.druid.sql.ast.statement.SQLDropViewStatement;
import com.alibaba.druid.sql.ast.statement.SQLExplainStatement;
import com.alibaba.druid.sql.ast.statement.SQLExprHint;
import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
import com.alibaba.druid.sql.ast.statement.SQLForeignKeyImpl;
@@ -964,4 +965,14 @@ public class SQLASTVisitorAdapter implements SQLASTVisitor {
public boolean visit(SQLDropUserStatement x) {
return true;
}
@Override
public void endVisit(SQLExplainStatement x) {
}
@Override
public boolean visit(SQLExplainStatement x) {
return true;
}
}
@@ -0,0 +1,57 @@
/*
* 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.sql.mysql;
import java.util.List;
import org.junit.Assert;
import com.alibaba.druid.sql.MysqlTest;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser;
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlSchemaStatVisitor;
import com.alibaba.druid.stat.TableStat;
public class MySqlDescTest_0 extends MysqlTest {
public void test_0() throws Exception {
String sql = " Desc City";
MySqlStatementParser parser = new MySqlStatementParser(sql);
List<SQLStatement> statementList = parser.parseStatementList();
SQLStatement stmt = statementList.get(0);
print(statementList);
Assert.assertEquals(1, statementList.size());
MySqlSchemaStatVisitor visitor = new MySqlSchemaStatVisitor();
stmt.accept(visitor);
System.out.println("Tables : " + visitor.getTables());
System.out.println("fields : " + visitor.getColumns());
System.out.println("coditions : " + visitor.getConditions());
System.out.println("orderBy : " + visitor.getOrderByColumns());
Assert.assertEquals(1, visitor.getTables().size());
Assert.assertEquals(0, visitor.getColumns().size());
Assert.assertEquals(0, visitor.getConditions().size());
Assert.assertTrue(visitor.getTables().containsKey(new TableStat.Name("City")));
// Assert.assertTrue(visitor.getTables().containsKey(new TableStat.Name("t2")));
// Assert.assertTrue(visitor.getColumns().contains(new Column("t2", "id")));
}
}
@@ -32,13 +32,13 @@ public class MySqlDescribteTest extends MysqlTest {
MySqlStatementParser parser = new MySqlStatementParser(sql);
List<SQLStatement> statementList = parser.parseStatementList();
SQLStatement statemen = statementList.get(0);
SQLStatement stmt = statementList.get(0);
print(statementList);
Assert.assertEquals(1, statementList.size());
MySqlSchemaStatVisitor visitor = new MySqlSchemaStatVisitor();
statemen.accept(visitor);
stmt.accept(visitor);
System.out.println("Tables : " + visitor.getTables());
System.out.println("fields : " + visitor.getColumns());
@@ -0,0 +1,57 @@
/*
* 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.sql.mysql;
import java.util.List;
import org.junit.Assert;
import com.alibaba.druid.sql.MysqlTest;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser;
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlSchemaStatVisitor;
import com.alibaba.druid.stat.TableStat;
public class MySqlExplainTest_0 extends MysqlTest {
public void test_0() throws Exception {
String sql = "explain SELECT * FROM sonar.groups where id = 1";
MySqlStatementParser parser = new MySqlStatementParser(sql);
List<SQLStatement> statementList = parser.parseStatementList();
SQLStatement stmt = statementList.get(0);
print(statementList);
Assert.assertEquals(1, statementList.size());
MySqlSchemaStatVisitor visitor = new MySqlSchemaStatVisitor();
stmt.accept(visitor);
System.out.println("Tables : " + visitor.getTables());
System.out.println("fields : " + visitor.getColumns());
System.out.println("coditions : " + visitor.getConditions());
System.out.println("orderBy : " + visitor.getOrderByColumns());
Assert.assertEquals(1, visitor.getTables().size());
Assert.assertEquals(2, visitor.getColumns().size());
Assert.assertEquals(1, visitor.getConditions().size());
Assert.assertTrue(visitor.getTables().containsKey(new TableStat.Name("sonar.groups")));
// Assert.assertTrue(visitor.getTables().containsKey(new TableStat.Name("t2")));
// Assert.assertTrue(visitor.getColumns().contains(new Column("t2", "id")));
}
}
@@ -30,14 +30,14 @@ public class MySqlSetTest_0 extends MysqlTest {
String sql = "SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ";
MySqlStatementParser parser = new MySqlStatementParser(sql);
List<SQLStatement> stmt = parser.parseStatementList();
SQLStatement statemen = stmt.get(0);
print(stmt);
List<SQLStatement> stmtList = parser.parseStatementList();
SQLStatement stmt = stmtList.get(0);
print(stmtList);
Assert.assertEquals(1, stmt.size());
Assert.assertEquals(1, stmtList.size());
MySqlSchemaStatVisitor visitor = new MySqlSchemaStatVisitor();
statemen.accept(visitor);
stmt.accept(visitor);
System.out.println("Tables : " + visitor.getTables());
System.out.println("fields : " + visitor.getColumns());
@@ -48,7 +48,7 @@ public class MySqlSetTest_0 extends MysqlTest {
Assert.assertEquals(0, visitor.getColumns().size());
Assert.assertEquals(0, visitor.getConditions().size());
String text = output(stmt);
String text = output(stmtList);
Assert.assertEquals("SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ", text);
}