improve sql parser for db2

This commit is contained in:
wenshao
2013-08-06 09:00:31 +08:00
parent 9aa627bb21
commit eea8492bbd
6 changed files with 215 additions and 23 deletions
@@ -27,6 +27,10 @@ public class DB2SelectQueryBlock extends SQLSelectQueryBlock implements DB2Objec
private Isolation isolation;
private boolean forReadOnly;
private SQLExpr optimizeFor;
public SQLExpr getFirst() {
return first;
}
@@ -65,6 +69,22 @@ public class DB2SelectQueryBlock extends SQLSelectQueryBlock implements DB2Objec
this.isolation = isolation;
}
public boolean isForReadOnly() {
return forReadOnly;
}
public void setForReadOnly(boolean forReadOnly) {
this.forReadOnly = forReadOnly;
}
public SQLExpr getOptimizeFor() {
return optimizeFor;
}
public void setOptimizeFor(SQLExpr optimizeFor) {
this.optimizeFor = optimizeFor;
}
public static enum Isolation {
RR, RS, CS, UR
}
@@ -35,6 +35,7 @@ public class DB2Lexer extends Lexer {
map.put("FETCH", Token.FETCH);
map.put("FIRST", Token.FIRST);
map.put("ONLY", Token.ONLY);
map.put("OPTIMIZE", Token.OPTIMIZE);
DEFAULT_DB2_KEYWORDS = new Keywords(map);
}
@@ -77,31 +77,57 @@ public class DB2SelectParser extends SQLSelectParser {
parseGroupBy(queryBlock);
if (lexer.token() == Token.FETCH) {
lexer.nextToken();
accept(Token.FIRST);
SQLExpr first = this.exprParser.primary();
queryBlock.setFirst(first);
if (identifierEquals("ROW") || identifierEquals("ROWS")) {
lexer.nextToken();
}
accept(Token.ONLY);
}
if (lexer.token() == Token.WITH) {
lexer.nextToken();
if (identifierEquals("RR")) {
queryBlock.setIsolation(Isolation.RR);
} else if (identifierEquals("RS")) {
queryBlock.setIsolation(Isolation.RS);
} else if (identifierEquals("CS")) {
queryBlock.setIsolation(Isolation.CS);
} else if (identifierEquals("UR")) {
queryBlock.setIsolation(Isolation.UR);
} else {
throw new ParserException("TODO");
for (;;) {
if (lexer.token() == Token.FETCH) {
lexer.nextToken();
accept(Token.FIRST);
SQLExpr first = this.exprParser.primary();
queryBlock.setFirst(first);
if (identifierEquals("ROW") || identifierEquals("ROWS")) {
lexer.nextToken();
}
accept(Token.ONLY);
continue;
}
lexer.nextToken();
if (lexer.token() == Token.WITH) {
lexer.nextToken();
if (identifierEquals("RR")) {
queryBlock.setIsolation(Isolation.RR);
} else if (identifierEquals("RS")) {
queryBlock.setIsolation(Isolation.RS);
} else if (identifierEquals("CS")) {
queryBlock.setIsolation(Isolation.CS);
} else if (identifierEquals("UR")) {
queryBlock.setIsolation(Isolation.UR);
} else {
throw new ParserException("TODO");
}
lexer.nextToken();
continue;
}
if (lexer.token() == Token.FOR) {
lexer.nextToken();
acceptIdentifier("READ");
accept(Token.ONLY);
queryBlock.setForReadOnly(true);
}
if (lexer.token() == Token.OPTIMIZE) {
lexer.nextToken();
accept(Token.FOR);
queryBlock.setOptimizeFor(this.expr());
if (identifierEquals("ROW")) {
lexer.nextToken();
} else {
acceptIdentifier("ROWS");
}
}
break;
}
return queryRest(queryBlock);
@@ -36,12 +36,23 @@ public class DB2OutputVisitor extends SQLASTOutputVisitor implements DB2ASTVisit
print(" ROWS ONLY");
}
if (x.isForReadOnly()) {
println();
print("FOR READ ONLY");
}
if (x.getIsolation() != null) {
println();
print("WITH ");
print(x.getIsolation().name());
}
if (x.getOptimizeFor() != null) {
println();
print("OPTIMIZE FOR ");
x.getOptimizeFor().accept(this);
}
return false;
}
@@ -0,0 +1,67 @@
/*
* 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.db2;
import java.util.List;
import org.junit.Assert;
import com.alibaba.druid.sql.DB2Test;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.dialect.db2.parser.DB2StatementParser;
import com.alibaba.druid.sql.dialect.db2.visitor.DB2SchemaStatVisitor;
import com.alibaba.druid.stat.TableStat;
import com.alibaba.druid.stat.TableStat.Column;
import com.alibaba.druid.util.JdbcConstants;
public class DB2SelectTest_3 extends DB2Test {
public void test_0() throws Exception {
String sql = "select * from t for read only";
DB2StatementParser parser = new DB2StatementParser(sql);
List<SQLStatement> statementList = parser.parseStatementList();
SQLStatement stmt = statementList.get(0);
print(statementList);
Assert.assertEquals(1, statementList.size());
DB2SchemaStatVisitor visitor = new DB2SchemaStatVisitor();
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(1, visitor.getColumns().size());
Assert.assertEquals(0, visitor.getConditions().size());
Assert.assertTrue(visitor.getTables().containsKey(new TableStat.Name("t")));
Assert.assertTrue(visitor.getColumns().contains(new Column("t", "*")));
// Assert.assertTrue(visitor.getColumns().contains(new Column("mytable", "first_name")));
// Assert.assertTrue(visitor.getColumns().contains(new Column("mytable", "full_name")));
String output = SQLUtils.toSQLString(stmt, JdbcConstants.DB2);
Assert.assertEquals("SELECT *" //
+ "\nFROM t"//
+ "\nFOR READ ONLY", //
output);
}
}
@@ -0,0 +1,67 @@
/*
* 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.db2;
import java.util.List;
import org.junit.Assert;
import com.alibaba.druid.sql.DB2Test;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.dialect.db2.parser.DB2StatementParser;
import com.alibaba.druid.sql.dialect.db2.visitor.DB2SchemaStatVisitor;
import com.alibaba.druid.stat.TableStat;
import com.alibaba.druid.stat.TableStat.Column;
import com.alibaba.druid.util.JdbcConstants;
public class DB2SelectTest_4 extends DB2Test {
public void test_0() throws Exception {
String sql = "select * from t OPTIMIZE FOR 10 ROWS";
DB2StatementParser parser = new DB2StatementParser(sql);
List<SQLStatement> statementList = parser.parseStatementList();
SQLStatement stmt = statementList.get(0);
print(statementList);
Assert.assertEquals(1, statementList.size());
DB2SchemaStatVisitor visitor = new DB2SchemaStatVisitor();
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(1, visitor.getColumns().size());
Assert.assertEquals(0, visitor.getConditions().size());
Assert.assertTrue(visitor.getTables().containsKey(new TableStat.Name("t")));
Assert.assertTrue(visitor.getColumns().contains(new Column("t", "*")));
// Assert.assertTrue(visitor.getColumns().contains(new Column("mytable", "first_name")));
// Assert.assertTrue(visitor.getColumns().contains(new Column("mytable", "full_name")));
String output = SQLUtils.toSQLString(stmt, JdbcConstants.DB2);
Assert.assertEquals("SELECT *" //
+ "\nFROM t"//
+ "\nOPTIMIZE FOR 10", //
output);
}
}