add mapping support

This commit is contained in:
温少
2012-03-12 16:31:58 +08:00
parent 6a493d1e3b
commit 05e310f36d
13 changed files with 449 additions and 42 deletions
@@ -0,0 +1,23 @@
package com.alibaba.druid.mapping;
public class DruidMappingException extends RuntimeException {
private static final long serialVersionUID = 1L;
public DruidMappingException(){
super();
}
public DruidMappingException(String message, Throwable cause){
super(message, cause);
}
public DruidMappingException(String message){
super(message);
}
public DruidMappingException(Throwable cause){
super(cause);
}
}
@@ -1,15 +1,24 @@
package com.alibaba.druid.mapping;
import java.util.ArrayList;
import java.util.List;
import java.util.LinkedHashMap;
import java.util.Map;
public class Entity {
private String name;
private String description;
private String tableName;
private String name;
private String description;
private String tableName;
private List<Property> properties = new ArrayList<Property>();
private Map<String, Property> properties = new LinkedHashMap<String, Property>();
public Entity(){
}
public Entity(String name, String description, String tableName){
this.name = name;
this.description = description;
this.tableName = tableName;
}
public String getName() {
return name;
@@ -35,11 +44,30 @@ public class Entity {
this.tableName = tableName;
}
public List<Property> getProperties() {
public void addProperty(Property property) {
this.properties.put(property.getName(), property);
}
public Property getProperty(String name) {
Property prop = this.properties.get(name);
if (prop == null) {
for (Map.Entry<String, Property> entry : properties.entrySet()) {
if (entry.getKey().equalsIgnoreCase(name)) {
prop = entry.getValue();
break;
}
}
}
return prop;
}
public Map<String, Property> getProperties() {
return properties;
}
public void setProperties(List<Property> properties) {
public void setProperties(Map<String, Property> properties) {
this.properties = properties;
}
@@ -1,18 +1,150 @@
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.SQLSelectItem;
import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock;
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlASTVisitorAdapter;
public class EntityMapingMySqlVisitor extends MySqlASTVisitorAdapter {
private final Entity entity;
private final LinkedHashMap<String, Entity> entities;
public EntityMapingMySqlVisitor(Entity entity){
super();
this.entity = entity;
public EntityMapingMySqlVisitor(LinkedHashMap<String, Entity> entities){
this.entities = entities;
}
public Entity getEntity() {
public Map<String, Entity> getEntities() {
return entities;
}
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(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);
}
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);
}
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() + '"'));
}
}
public boolean visit(SQLIdentifierExpr x) {
String propertyName = x.getName();
Property property = null;
for (Entity entity : this.entities.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 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;
}
}
@@ -0,0 +1,63 @@
package com.alibaba.druid.mapping;
import java.util.LinkedHashMap;
import com.alibaba.druid.sql.SQLUtils;
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;
public class MappingEngine {
private LinkedHashMap<String, Entity> entities = new LinkedHashMap<String, Entity>();
private Integer maxLimit;
public Integer getMaxLimit() {
return maxLimit;
}
public void setMaxLimit(Integer maxLimit) {
this.maxLimit = maxLimit;
}
public LinkedHashMap<String, Entity> getEntities() {
return entities;
}
public void addEntity(Entity entity) {
this.entities.put(entity.getName(), entity);
}
public EntityMapingMySqlVisitor createMappingVisitor() {
return new EntityMapingMySqlVisitor(entities);
}
public String explain(String sql) {
MySqlSelectQueryBlock query = explainToSQLObject(sql);
if (this.maxLimit != null) {
if (query.getLimit() == null) {
Limit limit = new Limit();
limit.setRowCount(new SQLNumberExpr(maxLimit));
query.setLimit(limit);
} else {
SQLNumberExpr rowCountExpr = (SQLNumberExpr) query.getLimit().getRowCount();
int rowCount = rowCountExpr.getNumber().intValue();
if (rowCount > maxLimit.intValue()) {
rowCountExpr.setNumber(maxLimit);
}
}
}
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;
}
}
@@ -3,8 +3,18 @@ package com.alibaba.druid.mapping;
public class Property {
private String name;
private String desciption;
private String dbColumnName;
public Property(){
}
public Property(String name, String desciption, String dbColumnName){
this.name = name;
this.desciption = desciption;
this.dbColumnName = dbColumnName;
}
public String getName() {
return name;
}
@@ -21,4 +31,12 @@ public class Property {
this.dbColumnName = dbColumnName;
}
public String getDesciption() {
return desciption;
}
public void setDesciption(String desciption) {
this.desciption = desciption;
}
}
@@ -0,0 +1,34 @@
package com.alibaba.druid.sql;
import com.alibaba.druid.sql.ast.SQLObject;
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlOutputVisitor;
import com.alibaba.druid.sql.dialect.oracle.visitor.OracleOutputVisitor;
import com.alibaba.druid.sql.dialect.postgresql.visitor.PGOutputVisitor;
public class SQLUtils {
public static String toMySqlString(SQLObject sqlObject) {
StringBuilder out = new StringBuilder();
sqlObject.accept(new MySqlOutputVisitor(out));
String sql = out.toString();
return sql;
}
public static String toOracleString(SQLObject sqlObject) {
StringBuilder out = new StringBuilder();
sqlObject.accept(new OracleOutputVisitor(out));
String sql = out.toString();
return sql;
}
public static String toPGString(SQLObject sqlObject) {
StringBuilder out = new StringBuilder();
sqlObject.accept(new PGOutputVisitor(out));
String sql = out.toString();
return sql;
}
}
@@ -27,8 +27,10 @@ public class SQLExprTableSource extends SQLTableSourceImpl {
public SQLExprTableSource(){
}
public SQLExprTableSource(SQLExpr expr){
this.expr = expr;
}
public SQLExpr getExpr() {
return this.expr;
@@ -1,16 +0,0 @@
package com.alibaba.druid.sql.dialect.mysql.visitor;
import java.util.HashMap;
import java.util.Map;
import com.alibaba.druid.sql.ast.SQLExpr;
public class MySqlMappingVisitor extends MySqlASTVisitorAdapter {
private final Map<String, SQLExpr> mapping = new HashMap<String, SQLExpr>();
public void addMapping(String column, String targetExpr) {
}
}
@@ -85,14 +85,22 @@ import com.alibaba.druid.sql.ast.statement.SQLUpdateStatement;
public class SQLASTOutputVisitor extends SQLASTVisitorAdapter {
protected Appendable appender;
private String indent = "\t";
private int indentCount = 0;
protected final Appendable appender;
private String indent = "\t";
private int indentCount = 0;
public SQLASTOutputVisitor(Appendable appender){
this.appender = appender;
}
public int getIndentCount() {
return indentCount;
}
public Appendable getAppender() {
return appender;
}
public void decrementIndent() {
this.indentCount -= 1;
}
@@ -213,8 +221,8 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter {
if (x.getLeft() instanceof SQLBinaryOpExpr) {
SQLBinaryOpExpr left = (SQLBinaryOpExpr) x.getLeft();
boolean leftRational = left.getOperator() == SQLBinaryOperator.BooleanAnd
|| left.getOperator() == SQLBinaryOperator.BooleanOr;
|| left.getOperator() == SQLBinaryOperator.BooleanOr;
if (left.getOperator().priority > x.getOperator().priority) {
if (leftRational) {
incrementIndent();
@@ -222,7 +230,7 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter {
print('(');
left.accept(this);
print(')');
if (leftRational) {
decrementIndent();
}
@@ -257,11 +265,11 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter {
if (rightRational) {
incrementIndent();
}
print('(');
right.accept(this);
print(')');
if (rightRational) {
decrementIndent();
}
@@ -985,5 +993,5 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter {
return false;
}
}
@@ -135,7 +135,7 @@ public interface SQLASTVisitor {
boolean visit(SQLExistsExpr x);
boolean visit(SQLIdentifierExpr astNode);
boolean visit(SQLIdentifierExpr x);
boolean visit(SQLInListExpr x);
@@ -172,7 +172,7 @@ public class SQLASTVisitorAdapter implements SQLASTVisitor {
return true;
}
public boolean visit(SQLIdentifierExpr astNode) {
public boolean visit(SQLIdentifierExpr x) {
return true;
}
@@ -22,21 +22,28 @@ import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.StringWriter;
import java.math.BigDecimal;
import java.net.URL;
import java.sql.Connection;
import java.sql.Date;
import java.sql.Driver;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Types;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import com.alibaba.druid.logging.Log;
import com.alibaba.druid.logging.LogFactory;
import com.alibaba.druid.mapping.DruidMappingException;
/**
* @author wenshao<szujobs@hotmail.com>
@@ -520,6 +527,69 @@ public final class JdbcUtils {
}
}
public static List<Map<String, Object>> executeQuery(Connection conn, String sql, List<Object> parameters) {
List<Map<String, Object>> rows = new ArrayList<Map<String, Object>>();
PreparedStatement stmt = null;
ResultSet rs = null;
try {
stmt = conn.prepareStatement(sql);
for (int i = 0, size = parameters.size(); i < size; ++i) {
Object val = parameters.get(i);
int paramIndex = i + 1;
if (val == null) {
stmt.setNull(paramIndex, Types.VARCHAR);
} else if (val instanceof BigDecimal) {
stmt.setBigDecimal(paramIndex, (BigDecimal) val);
} else if (val instanceof String) {
stmt.setString(paramIndex, (String) val);
} else if (val instanceof Date) {
long time = ((Date) val).getTime();
stmt.setTimestamp(paramIndex, new java.sql.Timestamp(time));
} else if (val instanceof Byte) {
stmt.setByte(paramIndex, (Byte) val);
} else if (val instanceof Short) {
stmt.setShort(paramIndex, (Short) val);
} else if (val instanceof Integer) {
stmt.setInt(paramIndex, (Integer) val);
} else if (val instanceof Long) {
stmt.setLong(paramIndex, (Long) val);
} else if (val instanceof Float) {
stmt.setFloat(paramIndex, (Float) val);
} else if (val instanceof Double) {
stmt.setDouble(paramIndex, (Double) val);
} else {
throw new DruidMappingException("not support parameters : " + val);
}
}
rs = stmt.executeQuery();
ResultSetMetaData rsMeta = rs.getMetaData();
while (rs.next()) {
Map<String, Object> row = new LinkedHashMap<String, Object>();
for (int i = 0, size = rsMeta.getColumnCount(); i < size; ++i) {
String columName = rsMeta.getColumnName(i + 1);
Object value = rs.getObject(i + 1);
row.put(columName, value);
}
rows.add(row);
}
} catch (SQLException e) {
throw new DruidMappingException("execute error", e);
} finally {
JdbcUtils.close(rs);
JdbcUtils.close(stmt);
}
return rows;
}
public static String toString(StackTraceElement[] stackTrace) {
StringBuilder buf = new StringBuilder();
for (StackTraceElement item : stackTrace) {
@@ -0,0 +1,45 @@
package com.alibaba.druid.bvt.mapping;
import junit.framework.TestCase;
import org.junit.Assert;
import com.alibaba.druid.mapping.Entity;
import com.alibaba.druid.mapping.MappingEngine;
import com.alibaba.druid.mapping.Property;
public class MappingVisitorTest extends TestCase {
MappingEngine engine = new MappingEngine();
protected void setUp() throws Exception {
Entity entity = new Entity();
entity.setName("设备");
entity.setDescription("Device");
entity.setTableName("device");
entity.addProperty(new Property("编号", "", "serviceTag"));
entity.addProperty(new Property("IP地址", "", "ip"));
engine.addEntity(entity);
}
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\nWHERE ip = '127.0.0.1'",
engine.explain("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\nWHERE ip = '127.0.0.1'\nLIMIT 10",
engine.explain("select 编号, IP地址 WHERE IP地址 = '127.0.0.1'"));
engine.setMaxLimit(null);
}
}