mirror of
https://github.com/alibaba/druid.git
synced 2023-03-04 19:17:16 +00:00
improve sql parser
This commit is contained in:
@@ -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
-14
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+8
-21
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user