add mapping support

This commit is contained in:
温少
2012-03-12 18:04:06 +08:00
11 changed files with 294 additions and 106 deletions
@@ -7,6 +7,7 @@ import com.alibaba.druid.sql.ast.expr.SQLNumberExpr;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock.Limit;
import com.alibaba.druid.sql.dialect.mysql.parser.MySqlSelectParser;
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
public class MappingEngine {
@@ -29,13 +30,22 @@ public class MappingEngine {
this.entities.put(entity.getName(), entity);
}
public MySqlMappingVisitor createMappingVisitor() {
public SQLASTVisitor createMySqlMappingVisitor() {
return new MySqlMappingVisitor(entities);
}
public String explain(String sql) {
MySqlSelectQueryBlock query = explainToSQLObject(sql);
public String explainToMySql(String sql) {
MySqlSelectQueryBlock query = explainToMySqlObject(sql);
query.accept(this.createMySqlMappingVisitor());
return SQLUtils.toMySqlString(query);
}
public MySqlSelectQueryBlock explainToMySqlObject(String sql) {
MySqlSelectParser selectParser = new MySqlSelectParser(sql);
MySqlSelectQueryBlock query = (MySqlSelectQueryBlock) selectParser.query();
if (this.maxLimit != null) {
if (query.getLimit() == null) {
Limit limit = new Limit();
@@ -49,15 +59,7 @@ public class MappingEngine {
}
}
}
query.accept(this.createMappingVisitor());
return SQLUtils.toMySqlString(query);
}
public MySqlSelectQueryBlock explainToSQLObject(String sql) {
MySqlSelectParser selectParser = new MySqlSelectParser(sql);
MySqlSelectQueryBlock query = (MySqlSelectQueryBlock) selectParser.query();
return query;
}
}
@@ -0,0 +1,15 @@
package com.alibaba.druid.mapping;
import java.util.Map;
import com.alibaba.druid.sql.ast.statement.SQLTableSource;
public interface MappingVisitor {
Entity getFirstEntity();
Entity getEntity(String name);
Map<String, Entity> getEntities();
Map<String, SQLTableSource> getTableSources();
}
@@ -0,0 +1,103 @@
package com.alibaba.druid.mapping;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.expr.SQLAllColumnExpr;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
import com.alibaba.druid.sql.ast.statement.SQLSelectItem;
import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock;
import com.alibaba.druid.sql.ast.statement.SQLTableSource;
public class MappingVisitorUtils {
public static boolean visit(MappingVisitor visitor, SQLExprTableSource x) {
SQLExpr expr = x.getExpr();
if (expr instanceof SQLIdentifierExpr) {
SQLIdentifierExpr tableExpr = (SQLIdentifierExpr) expr;
String entityName = tableExpr.getName();
Entity entity = visitor.getEntity(entityName);
if (entity == null) {
throw new DruidMappingException("entity not foudn : " + entityName);
}
tableExpr.setName(entity.getTableName());
}
if (x.getAlias() != null) {
visitor.getTableSources().put(x.getAlias(), x);
}
return false;
}
public static boolean visit(MappingVisitor visitor, SQLTableSource x) {
if (x.getAlias() != null) {
visitor.getTableSources().put(x.getAlias(), x);
}
return true;
}
public static void fillSelectList(MappingVisitor visitor, SQLSelectQueryBlock x) {
Entity entity = visitor.getFirstEntity();
for (Property item : entity.getProperties().values()) {
x.getSelectList().add(new SQLSelectItem(new SQLIdentifierExpr(item.getName()), '"' + item.getName() + '"'));
}
}
public static boolean visit(MappingVisitor visitor, SQLIdentifierExpr x) {
String propertyName = x.getName();
Property property = null;
for (Entity entity : visitor.getEntities().values()) {
property = entity.getProperty(propertyName);
if (property != null) {
break;
}
}
if (property == null) {
throw new DruidMappingException("property not found : " + propertyName);
}
String dbColumName = property.getDbColumnName();
x.setName(dbColumName);
if (x.getParent() instanceof SQLSelectItem) {
SQLSelectItem selectItem = (SQLSelectItem) x.getParent();
if (selectItem.getAlias() == null) {
selectItem.setAlias('"' + property.getName() + '"');
}
}
return false;
}
public static boolean visit(MappingVisitor visitor, SQLSelectQueryBlock x) {
if (x.getSelectList().size() == 0) {
fillSelectList(visitor, x);
}
if (x.getSelectList().size() == 1) {
if (x.getSelectList().get(0).getExpr() instanceof SQLAllColumnExpr) {
x.getSelectList().clear();
fillSelectList(visitor, x);
}
}
if (x.getFrom() == null) {
Entity firstEntity = visitor.getFirstEntity();
SQLExprTableSource from = new SQLExprTableSource(new SQLIdentifierExpr(firstEntity.getName()));
x.setFrom(from);
}
for (SQLSelectItem item : x.getSelectList()) {
item.setParent(x);
}
return true;
}
}
@@ -3,23 +3,29 @@ package com.alibaba.druid.mapping;
import java.util.LinkedHashMap;
import java.util.Map;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.expr.SQLAllColumnExpr;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
import com.alibaba.druid.sql.ast.statement.SQLJoinTableSource;
import com.alibaba.druid.sql.ast.statement.SQLSelectItem;
import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock;
import com.alibaba.druid.sql.ast.statement.SQLSubqueryTableSource;
import com.alibaba.druid.sql.ast.statement.SQLTableSource;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock;
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlASTVisitorAdapter;
public class MySqlMappingVisitor extends MySqlASTVisitorAdapter {
public class MySqlMappingVisitor extends MySqlASTVisitorAdapter implements MappingVisitor {
private final LinkedHashMap<String, Entity> entities;
private final Map<String, SQLTableSource> tableSources = new LinkedHashMap<String, SQLTableSource>();
public MySqlMappingVisitor(LinkedHashMap<String, Entity> entities){
this.entities = entities;
}
public Map<String, SQLTableSource> getTableSources() {
return tableSources;
}
public Map<String, Entity> getEntities() {
return entities;
}
@@ -53,98 +59,30 @@ public class MySqlMappingVisitor extends MySqlASTVisitorAdapter {
}
public boolean visit(MySqlSelectQueryBlock x) {
if (x.getSelectList().size() == 0) {
fillSelectList(x);
}
if (x.getSelectList().size() == 1) {
if (x.getSelectList().get(0).getExpr() instanceof SQLAllColumnExpr) {
x.getSelectList().clear();
fillSelectList(x);
}
}
if (x.getFrom() == null) {
Entity firstEntity = this.getFirstEntity();
SQLExprTableSource from = new SQLExprTableSource(new SQLIdentifierExpr(firstEntity.getName()));
x.setFrom(from);
}
for (SQLSelectItem item : x.getSelectList()) {
item.setParent(x);
}
return super.visit(x);
return MappingVisitorUtils.visit(this, x);
}
public boolean visit(SQLSelectQueryBlock x) {
if (x instanceof MySqlSelectQueryBlock) {
return visit((MySqlSelectQueryBlock) x);
}
if (x.getSelectList().size() == 0) {
fillSelectList(x);
}
for (SQLSelectItem item : x.getSelectList()) {
item.setParent(x);
}
return super.visit(x);
return MappingVisitorUtils.visit(this, x);
}
protected void fillSelectList(SQLSelectQueryBlock x) {
Entity entity = getFirstEntity();
for (Property item : entity.getProperties().values()) {
x.getSelectList().add(new SQLSelectItem(new SQLIdentifierExpr(item.getName()), '"' + item.getName() + '"'));
}
MappingVisitorUtils.fillSelectList(this, x);
}
public boolean visit(SQLIdentifierExpr x) {
String propertyName = x.getName();
return MappingVisitorUtils.visit(this, x);
}
Property property = null;
for (Entity entity : this.entities.values()) {
property = entity.getProperty(propertyName);
if (property != null) {
break;
}
}
public boolean visit(SQLSubqueryTableSource x) {
return MappingVisitorUtils.visit(this, x);
}
if (property == null) {
throw new DruidMappingException("property not found : " + propertyName);
}
String dbColumName = property.getDbColumnName();
x.setName(dbColumName);
if (x.getParent() instanceof SQLSelectItem) {
SQLSelectItem selectItem = (SQLSelectItem) x.getParent();
if (selectItem.getAlias() == null) {
selectItem.setAlias('"' + property.getName() + '"');
}
}
return false;
public boolean visit(SQLJoinTableSource x) {
return MappingVisitorUtils.visit(this, x);
}
public boolean visit(SQLExprTableSource x) {
SQLExpr expr = x.getExpr();
if (expr instanceof SQLIdentifierExpr) {
SQLIdentifierExpr tableExpr = (SQLIdentifierExpr) expr;
String entityName = tableExpr.getName();
Entity entity = this.getEntity(entityName);
if (entity == null) {
throw new DruidMappingException("entity not foudn : " + entityName);
}
tableExpr.setName(entity.getTableName());
}
return false;
return MappingVisitorUtils.visit(this, x);
}
}
@@ -0,0 +1,93 @@
package com.alibaba.druid.mapping;
import java.util.LinkedHashMap;
import java.util.Map;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
import com.alibaba.druid.sql.ast.statement.SQLJoinTableSource;
import com.alibaba.druid.sql.ast.statement.SQLSelectItem;
import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock;
import com.alibaba.druid.sql.ast.statement.SQLSubqueryTableSource;
import com.alibaba.druid.sql.ast.statement.SQLTableSource;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelectQueryBlock;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelectTableReference;
import com.alibaba.druid.sql.dialect.oracle.visitor.OracleASTVIsitorAdapter;
public class OracleMappingVisitor extends OracleASTVIsitorAdapter implements MappingVisitor {
private final LinkedHashMap<String, Entity> entities;
private final Map<String, SQLTableSource> tableSources = new LinkedHashMap<String, SQLTableSource>();
public OracleMappingVisitor(LinkedHashMap<String, Entity> entities) {
super();
this.entities = entities;
}
public LinkedHashMap<String, Entity> getEntities() {
return entities;
}
public Map<String, SQLTableSource> getTableSources() {
return tableSources;
}
public Entity getFirstEntity() {
for (Map.Entry<String, Entity> entry : entities.entrySet()) {
return entry.getValue();
}
return null;
}
public Entity getEntity(String name) {
Entity entity = this.entities.get(name);
if (entity == null) {
for (Map.Entry<String, Entity> entry : entities.entrySet()) {
if (entry.getKey().equalsIgnoreCase(name)) {
entity = entry.getValue();
break;
}
}
}
return entity;
}
public boolean visit(SQLSelectItem x) {
x.getExpr().setParent(x);
return true;
}
public boolean visit(OracleSelectQueryBlock x) {
return MappingVisitorUtils.visit(this, x);
}
public boolean visit(SQLSelectQueryBlock x) {
return MappingVisitorUtils.visit(this, x);
}
protected void fillSelectList(SQLSelectQueryBlock x) {
MappingVisitorUtils.fillSelectList(this, x);
}
public boolean visit(SQLIdentifierExpr x) {
return MappingVisitorUtils.visit(this, x);
}
public boolean visit(SQLSubqueryTableSource x) {
return MappingVisitorUtils.visit(this, x);
}
public boolean visit(SQLJoinTableSource x) {
return MappingVisitorUtils.visit(this, x);
}
public boolean visit(SQLExprTableSource x) {
return MappingVisitorUtils.visit(this, x);
}
public boolean visit(OracleSelectTableReference x) {
return MappingVisitorUtils.visit(this, x);
}
}
@@ -187,4 +187,8 @@ public interface MySqlASTVisitor extends SQLASTVisitor {
void endVisit(MySqlPartitionByKey x);
boolean visit(MySqlPartitionByKey x);
boolean visit(MySqlSelectQueryBlock x);
void endVisit(MySqlSelectQueryBlock x);
}
@@ -26,6 +26,7 @@ import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlReplicateStatement
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlResetStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlRollbackStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectGroupBy;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock.Limit;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowColumnsStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowDatabasesStatement;
@@ -400,4 +401,14 @@ public class MySqlASTVisitorAdapter extends SQLASTVisitorAdapter implements
return true;
}
@Override
public boolean visit(MySqlSelectQueryBlock x) {
return true;
}
@Override
public void endVisit(MySqlSelectQueryBlock x) {
}
}
@@ -1343,4 +1343,9 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV
}
return false;
}
@Override
public void endVisit(MySqlSelectQueryBlock x) {
}
}
@@ -5,6 +5,7 @@ import java.util.Map;
import com.alibaba.druid.sql.ast.SQLName;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.statement.SQLDropTableStatement;
import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock;
import com.alibaba.druid.sql.ast.statement.SQLSelectStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.MySqlKey;
import com.alibaba.druid.sql.dialect.mysql.ast.MySqlPrimaryKey;
@@ -32,6 +33,7 @@ import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlReplicateStatement
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlResetStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlRollbackStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectGroupBy;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock.Limit;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowColumnsStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlShowDatabasesStatement;
@@ -49,10 +51,11 @@ public class MySqlSchemaStatVisitor extends SchemaStatVisitor implements MySqlAS
public boolean visit(SQLSelectStatement x) {
setAliasMap();
getAliasMap().put("DUAL", null);
return true;
}
//DUAL
// DUAL
public boolean visit(MySqlDeleteStatement x) {
setAliasMap();
@@ -426,31 +429,45 @@ public class MySqlSchemaStatVisitor extends SchemaStatVisitor implements MySqlAS
public boolean visit(UserSpecification x) {
return true;
}
@Override
public void endVisit(MySqlDropUser x) {
}
@Override
public boolean visit(MySqlDropUser x) {
return true;
}
@Override
public void endVisit(MySqlDropTableStatement x) {
}
@Override
public boolean visit(MySqlDropTableStatement x) {
return visit((SQLDropTableStatement) x);
}
@Override
public void endVisit(MySqlPartitionByKey x) {
}
@Override
public boolean visit(MySqlPartitionByKey x) {
accept(x.getColumns());
return false;
}
@Override
public boolean visit(MySqlSelectQueryBlock x) {
return this.visit((SQLSelectQueryBlock) x);
}
@Override
public void endVisit(MySqlSelectQueryBlock x) {
}
}
@@ -198,7 +198,7 @@ public interface SQLASTVisitor {
boolean visit(SQLSelectQueryBlock x);
void endVisit(SQLSelectQueryBlock x);
boolean visit(SQLExprTableSource x);
void endVisit(SQLExprTableSource x);
@@ -26,18 +26,18 @@ public class MappingVisitorTest extends TestCase {
public void test_0() throws Exception {
Assert.assertEquals("SELECT serviceTag AS \"编号\", ip AS \"IP地址\"\nFROM device", engine.explain("select *"));
Assert.assertEquals("SELECT serviceTag AS \"编号\", ip AS \"IP地址\"\nFROM device", engine.explainToMySql("select *"));
Assert.assertEquals("SELECT serviceTag AS \"编号\", ip AS \"IP地址\"\nFROM device\nWHERE ip = '127.0.0.1'",
engine.explain("select 编号, IP地址 WHERE IP地址 = '127.0.0.1'"));
engine.explainToMySql("select 编号, IP地址 WHERE IP地址 = '127.0.0.1'"));
}
public void test_1() throws Exception {
engine.setMaxLimit(10);
Assert.assertEquals("SELECT serviceTag AS \"编号\", ip AS \"IP地址\"\nFROM device\nLIMIT 10", engine.explain("select *"));
Assert.assertEquals("SELECT serviceTag AS \"编号\", ip AS \"IP地址\"\nFROM device\nLIMIT 10", engine.explainToMySql("select *"));
Assert.assertEquals("SELECT serviceTag AS \"编号\", ip AS \"IP地址\"\nFROM device\nWHERE ip = '127.0.0.1'\nLIMIT 10",
engine.explain("select 编号, IP地址 WHERE IP地址 = '127.0.0.1'"));
engine.explainToMySql("select 编号, IP地址 WHERE IP地址 = '127.0.0.1'"));
engine.setMaxLimit(null);