diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleEvalVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleEvalVisitor.java new file mode 100644 index 0000000000..bca2824152 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/visitor/OracleEvalVisitor.java @@ -0,0 +1,64 @@ +package com.alibaba.druid.sql.dialect.oracle.visitor; + +import java.util.ArrayList; +import java.util.List; + +import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr; +import com.alibaba.druid.sql.ast.expr.SQLCharExpr; +import com.alibaba.druid.sql.ast.expr.SQLVariantRefExpr; +import com.alibaba.druid.sql.visitor.SQLEvalVisitor; +import com.alibaba.druid.sql.visitor.SQLEvalVisitorUtils; + + +public class OracleEvalVisitor extends OracleASTVisitorAdapter implements SQLEvalVisitor { + private List parameters = new ArrayList(); + + private int variantIndex = -1; + + private boolean markVariantIndex = true; + + public OracleEvalVisitor(){ + this(new ArrayList(1)); + } + + public OracleEvalVisitor(List parameters){ + this.parameters = parameters; + } + + public List getParameters() { + return parameters; + } + + public void setParameters(List parameters) { + this.parameters = parameters; + } + + public boolean visit(SQLCharExpr x) { + return SQLEvalVisitorUtils.visit(this, x); + } + + public int incrementAndGetVariantIndex() { + return ++variantIndex; + } + + public int getVariantIndex() { + return variantIndex; + } + + public boolean visit(SQLVariantRefExpr x) { + return SQLEvalVisitorUtils.visit(this, x); + } + + public boolean visit(SQLBinaryOpExpr x) { + return SQLEvalVisitorUtils.visit(this, x); + } + + public boolean isMarkVariantIndex() { + return markVariantIndex; + } + + public void setMarkVariantIndex(boolean markVariantIndex) { + this.markVariantIndex = markVariantIndex; + } + +} diff --git a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGEvalVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGEvalVisitor.java new file mode 100644 index 0000000000..f378068366 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGEvalVisitor.java @@ -0,0 +1,64 @@ +package com.alibaba.druid.sql.dialect.postgresql.visitor; + +import java.util.ArrayList; +import java.util.List; + +import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr; +import com.alibaba.druid.sql.ast.expr.SQLCharExpr; +import com.alibaba.druid.sql.ast.expr.SQLVariantRefExpr; +import com.alibaba.druid.sql.visitor.SQLEvalVisitor; +import com.alibaba.druid.sql.visitor.SQLEvalVisitorUtils; + + +public class PGEvalVisitor extends PGASTVisitorAdapter implements SQLEvalVisitor { + private List parameters = new ArrayList(); + + private int variantIndex = -1; + + private boolean markVariantIndex = true; + + public PGEvalVisitor(){ + this(new ArrayList(1)); + } + + public PGEvalVisitor(List parameters){ + this.parameters = parameters; + } + + public List getParameters() { + return parameters; + } + + public void setParameters(List parameters) { + this.parameters = parameters; + } + + public boolean visit(SQLCharExpr x) { + return SQLEvalVisitorUtils.visit(this, x); + } + + public int incrementAndGetVariantIndex() { + return ++variantIndex; + } + + public int getVariantIndex() { + return variantIndex; + } + + public boolean visit(SQLVariantRefExpr x) { + return SQLEvalVisitorUtils.visit(this, x); + } + + public boolean visit(SQLBinaryOpExpr x) { + return SQLEvalVisitorUtils.visit(this, x); + } + + public boolean isMarkVariantIndex() { + return markVariantIndex; + } + + public void setMarkVariantIndex(boolean markVariantIndex) { + this.markVariantIndex = markVariantIndex; + } + +} diff --git a/src/main/java/com/alibaba/druid/sql/visitor/SQLEvalVisitorUtils.java b/src/main/java/com/alibaba/druid/sql/visitor/SQLEvalVisitorUtils.java index e88303318e..ec1674a4bb 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SQLEvalVisitorUtils.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SQLEvalVisitorUtils.java @@ -22,6 +22,8 @@ import com.alibaba.druid.sql.ast.expr.SQLCharExpr; import com.alibaba.druid.sql.ast.expr.SQLNumericLiteralExpr; import com.alibaba.druid.sql.ast.expr.SQLVariantRefExpr; import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlEvalVisitorImpl; +import com.alibaba.druid.sql.dialect.oracle.visitor.OracleEvalVisitor; +import com.alibaba.druid.sql.dialect.postgresql.visitor.PGEvalVisitor; import com.alibaba.druid.util.JdbcUtils; public class SQLEvalVisitorUtils { @@ -47,15 +49,19 @@ public class SQLEvalVisitorUtils { return sqlObject.getAttributes().get(EVAL_VALUE); } - + public static Object eval(String dbType, SQLObject sqlObject, List parameters) { + return eval(dbType, sqlObject, parameters, true); + } + + public static Object eval(String dbType, SQLObject sqlObject, List parameters, boolean throwError) { SQLEvalVisitor visitor = createEvalVisitor(dbType); visitor.setParameters(parameters); sqlObject.accept(visitor); Object value = getValue(sqlObject); if (value == null) { - if (!sqlObject.getAttributes().containsKey(EVAL_VALUE)) { + if (throwError && !sqlObject.getAttributes().containsKey(EVAL_VALUE)) { throw new DruidRuntimeException("eval error : " + SQLUtils.toSQLString(sqlObject, dbType)); } } @@ -67,6 +73,14 @@ public class SQLEvalVisitorUtils { if (JdbcUtils.MYSQL.equals(dbType)) { return new MySqlEvalVisitorImpl(); } + + if (JdbcUtils.ORACLE.equals(dbType)) { + return new OracleEvalVisitor(); + } + + if (JdbcUtils.POSTGRESQL.equals(dbType)) { + return new PGEvalVisitor(); + } return new SQLEvalVisitorImpl(); } diff --git a/src/main/java/com/alibaba/druid/sql/visitor/SchemaStatVisitor.java b/src/main/java/com/alibaba/druid/sql/visitor/SchemaStatVisitor.java index 160e6667ad..7161b17f54 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SchemaStatVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SchemaStatVisitor.java @@ -12,6 +12,7 @@ import com.alibaba.druid.sql.ast.SQLExpr; import com.alibaba.druid.sql.ast.SQLName; import com.alibaba.druid.sql.ast.SQLObject; import com.alibaba.druid.sql.ast.SQLOrderBy; +import com.alibaba.druid.sql.ast.SQLOrderingSpecification; import com.alibaba.druid.sql.ast.expr.SQLAggregateExpr; import com.alibaba.druid.sql.ast.expr.SQLAllColumnExpr; import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr; @@ -53,9 +54,9 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter { protected final HashMap tableStats = new LinkedHashMap(); protected final Set columns = new LinkedHashSet(); - protected final List conditions = new ArrayList(); + protected final List conditions = new ArrayList(); protected final Set relationships = new LinkedHashSet(); - protected final Set orderByColumns = new LinkedHashSet(); + protected final List orderByColumns = new ArrayList(); protected final Set groupByColumns = new LinkedHashSet(); protected final Map subQueryMap = new LinkedHashMap(); @@ -192,6 +193,9 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter { public OrderByStatVisitor(SQLOrderBy orderBy){ this.orderBy = orderBy; + for (SQLSelectOrderByItem item : orderBy.getItems()) { + item.getExpr().setParent(item); + } } public SQLOrderBy getOrderBy() { @@ -206,9 +210,9 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter { } if (currentTable != null) { - orderByColumns.add(new Column(currentTable, x.getName())); + addOrderByColumn(currentTable, x.getName(), x); } else { - orderByColumns.add(new Column("UNKOWN", x.getName())); + addOrderByColumn("UNKOWN", x.getName(), x); } return false; } @@ -224,12 +228,24 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter { owner = aliasWrap(owner); if (owner != null) { - orderByColumns.add(new Column(owner, x.getName())); + addOrderByColumn(owner, x.getName(), x); } } return false; } + + public void addOrderByColumn(String table, String columnName, SQLObject expr) { + Column column = new Column(table, columnName); + + SQLObject parent = expr.getParent(); + if (parent instanceof SQLSelectOrderByItem) { + SQLOrderingSpecification type = ((SQLSelectOrderByItem) parent).getType(); + column.getAttributes().put("orderBy.type", type); + } + + orderByColumns.add(column); + } } public boolean visit(SQLOrderBy x) { @@ -258,7 +274,7 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter { return relationships; } - public Set getOrderByColumns() { + public List getOrderByColumns() { return orderByColumns; } @@ -340,13 +356,13 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter { condition.setOperator(operator); this.conditions.add(condition); } - + for (SQLExpr item : valueExprs) { - Object value = SQLEvalVisitorUtils.eval(getDbType(), item, parameters); + Object value = SQLEvalVisitorUtils.eval(getDbType(), item, parameters, false); condition.getValues().add(value); } } - + public String getDbType() { return null; } diff --git a/src/main/java/com/alibaba/druid/stat/TableStat.java b/src/main/java/com/alibaba/druid/stat/TableStat.java index 972b9db95d..98d3e624c0 100644 --- a/src/main/java/com/alibaba/druid/stat/TableStat.java +++ b/src/main/java/com/alibaba/druid/stat/TableStat.java @@ -16,7 +16,9 @@ package com.alibaba.druid.stat; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; public class TableStat { @@ -341,8 +343,10 @@ public class TableStat { public static class Column { - private String table; - private String name; + private String table; + private String name; + + private Map attributes = new HashMap(); public Column(){ @@ -369,6 +373,14 @@ public class TableStat { this.name = name; } + public Map getAttributes() { + return attributes; + } + + public void setAttributes(Map attributes) { + this.attributes = attributes; + } + public int hashCode() { int tableHashCode = table != null ? table.toLowerCase().hashCode() : 0; int nameHashCode = name != null ? name.toLowerCase().hashCode() : 0; diff --git a/src/test/java/com/alibaba/druid/bvt/sql/oracle/OracleSchemaStatVisitorTest.java b/src/test/java/com/alibaba/druid/bvt/sql/oracle/OracleSchemaStatVisitorTest.java index 7990fad787..6ad3e78409 100644 --- a/src/test/java/com/alibaba/druid/bvt/sql/oracle/OracleSchemaStatVisitorTest.java +++ b/src/test/java/com/alibaba/druid/bvt/sql/oracle/OracleSchemaStatVisitorTest.java @@ -6,17 +6,19 @@ import java.util.List; import junit.framework.Assert; import com.alibaba.druid.sql.OracleTest; +import com.alibaba.druid.sql.ast.SQLOrderingSpecification; import com.alibaba.druid.sql.ast.SQLStatement; import com.alibaba.druid.sql.dialect.oracle.parser.OracleStatementParser; import com.alibaba.druid.sql.dialect.oracle.visitor.OracleSchemaStatVisitor; import com.alibaba.druid.stat.TableStat; +import com.alibaba.druid.stat.TableStat.Column; import com.alibaba.druid.stat.TableStat.Condition; public class OracleSchemaStatVisitorTest extends OracleTest { public void test_0() throws Exception { String sql = "SELECT id, name name from department d" + // - " WHERE d.id = ?"; + " WHERE d.id = ? order by name desc"; OracleStatementParser parser = new OracleStatementParser(sql); List statementList = parser.parseStatementList(); @@ -49,5 +51,8 @@ public class OracleSchemaStatVisitorTest extends OracleTest { Condition condition = visitor.getConditions().get(0); Assert.assertSame(parameters.get(0), condition.getValues().get(0)); + + Column orderByColumn = visitor.getOrderByColumns().iterator().next(); + Assert.assertEquals(SQLOrderingSpecification.DESC, orderByColumn.getAttributes().get("orderBy.type")); } }