From c6215482ae58e2d217f753bdfc5402eacb31e6d9 Mon Sep 17 00:00:00 2001 From: wenshao Date: Sat, 10 Nov 2012 23:53:30 +0800 Subject: [PATCH] improve SQLEvalVisitor --- .../mysql/visitor/MySqlEvalVisitorImpl.java | 23 ++++++ .../oracle/visitor/OracleEvalVisitor.java | 16 ++++ .../postgresql/visitor/PGEvalVisitor.java | 18 +++- .../druid/sql/visitor/SQLEvalVisitorImpl.java | 16 ++++ .../sql/visitor/SQLEvalVisitorUtils.java | 82 +++++++++++++++---- .../com/alibaba/druid/util/JdbcConstants.java | 41 ++++++++++ .../com/alibaba/druid/util/JdbcUtils.java | 39 +-------- .../druid/bvt/sql/eval/EvalCaseThen.java | 15 ++++ .../alibaba/druid/bvt/sql/eval/EvalTest.java | 42 ++++++++-- 9 files changed, 231 insertions(+), 61 deletions(-) create mode 100644 src/main/java/com/alibaba/druid/util/JdbcConstants.java create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/eval/EvalCaseThen.java diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlEvalVisitorImpl.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlEvalVisitorImpl.java index fda0c972a6..c137e11f24 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlEvalVisitorImpl.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlEvalVisitorImpl.java @@ -19,8 +19,12 @@ import java.util.ArrayList; import java.util.List; import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr; +import com.alibaba.druid.sql.ast.expr.SQLCaseExpr; import com.alibaba.druid.sql.ast.expr.SQLCharExpr; +import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr; +import com.alibaba.druid.sql.ast.expr.SQLNumberExpr; import com.alibaba.druid.sql.ast.expr.SQLVariantRefExpr; +import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlBooleanExpr; import com.alibaba.druid.sql.visitor.SQLEvalVisitor; import com.alibaba.druid.sql.visitor.SQLEvalVisitorUtils; @@ -67,7 +71,26 @@ public class MySqlEvalVisitorImpl extends MySqlASTVisitorAdapter implements SQLE public boolean visit(SQLBinaryOpExpr x) { return SQLEvalVisitorUtils.visit(this, x); } + + public boolean visit(SQLIntegerExpr x) { + return SQLEvalVisitorUtils.visit(this, x); + } + public boolean visit(SQLNumberExpr x) { + return SQLEvalVisitorUtils.visit(this, x); + } + + @Override + public boolean visit(SQLCaseExpr x) { + return SQLEvalVisitorUtils.visit(this, x); + } + + @Override + public boolean visit(MySqlBooleanExpr x) { + x.getAttributes().put(EVAL_VALUE, x.getValue()); + return false; + } + public boolean isMarkVariantIndex() { return markVariantIndex; } 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 index 30849ec8bd..deab5de9a3 100644 --- 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 @@ -19,7 +19,10 @@ import java.util.ArrayList; import java.util.List; import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr; +import com.alibaba.druid.sql.ast.expr.SQLCaseExpr; import com.alibaba.druid.sql.ast.expr.SQLCharExpr; +import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr; +import com.alibaba.druid.sql.ast.expr.SQLNumberExpr; import com.alibaba.druid.sql.ast.expr.SQLVariantRefExpr; import com.alibaba.druid.sql.visitor.SQLEvalVisitor; import com.alibaba.druid.sql.visitor.SQLEvalVisitorUtils; @@ -67,6 +70,19 @@ public class OracleEvalVisitor extends OracleASTVisitorAdapter implements SQLEva public boolean visit(SQLBinaryOpExpr x) { return SQLEvalVisitorUtils.visit(this, x); } + + public boolean visit(SQLIntegerExpr x) { + return SQLEvalVisitorUtils.visit(this, x); + } + + public boolean visit(SQLNumberExpr x) { + return SQLEvalVisitorUtils.visit(this, x); + } + + @Override + public boolean visit(SQLCaseExpr x) { + return SQLEvalVisitorUtils.visit(this, x); + } public boolean isMarkVariantIndex() { return 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 index 5ed32bb47b..17e4515a15 100644 --- 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 @@ -19,13 +19,16 @@ import java.util.ArrayList; import java.util.List; import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr; +import com.alibaba.druid.sql.ast.expr.SQLCaseExpr; import com.alibaba.druid.sql.ast.expr.SQLCharExpr; +import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr; +import com.alibaba.druid.sql.ast.expr.SQLNumberExpr; 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; @@ -68,6 +71,19 @@ public class PGEvalVisitor extends PGASTVisitorAdapter implements SQLEvalVisitor return SQLEvalVisitorUtils.visit(this, x); } + public boolean visit(SQLIntegerExpr x) { + return SQLEvalVisitorUtils.visit(this, x); + } + + public boolean visit(SQLNumberExpr x) { + return SQLEvalVisitorUtils.visit(this, x); + } + + @Override + public boolean visit(SQLCaseExpr x) { + return SQLEvalVisitorUtils.visit(this, x); + } + public boolean isMarkVariantIndex() { return markVariantIndex; } diff --git a/src/main/java/com/alibaba/druid/sql/visitor/SQLEvalVisitorImpl.java b/src/main/java/com/alibaba/druid/sql/visitor/SQLEvalVisitorImpl.java index 52c18166be..80d6655437 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SQLEvalVisitorImpl.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SQLEvalVisitorImpl.java @@ -19,7 +19,10 @@ import java.util.ArrayList; import java.util.List; import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr; +import com.alibaba.druid.sql.ast.expr.SQLCaseExpr; import com.alibaba.druid.sql.ast.expr.SQLCharExpr; +import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr; +import com.alibaba.druid.sql.ast.expr.SQLNumberExpr; import com.alibaba.druid.sql.ast.expr.SQLVariantRefExpr; public class SQLEvalVisitorImpl extends SQLASTVisitorAdapter implements SQLEvalVisitor { @@ -66,6 +69,19 @@ public class SQLEvalVisitorImpl extends SQLASTVisitorAdapter implements SQLEvalV return SQLEvalVisitorUtils.visit(this, x); } + public boolean visit(SQLIntegerExpr x) { + return SQLEvalVisitorUtils.visit(this, x); + } + + public boolean visit(SQLNumberExpr x) { + return SQLEvalVisitorUtils.visit(this, x); + } + + @Override + public boolean visit(SQLCaseExpr x) { + return SQLEvalVisitorUtils.visit(this, x); + } + public boolean isMarkVariantIndex() { return 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 e0399eae82..9ab1b70f21 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SQLEvalVisitorUtils.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SQLEvalVisitorUtils.java @@ -31,6 +31,7 @@ import com.alibaba.druid.sql.SQLUtils; import com.alibaba.druid.sql.ast.SQLExpr; import com.alibaba.druid.sql.ast.SQLObject; import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr; +import com.alibaba.druid.sql.ast.expr.SQLCaseExpr; import com.alibaba.druid.sql.ast.expr.SQLCharExpr; import com.alibaba.druid.sql.ast.expr.SQLNumericLiteralExpr; import com.alibaba.druid.sql.ast.expr.SQLVariantRefExpr; @@ -106,6 +107,46 @@ public class SQLEvalVisitorUtils { x.putAttribute(EVAL_VALUE, x.getText()); return true; } + + public static boolean visit(SQLEvalVisitor visitor, SQLCaseExpr x) { + x.getValueExpr().accept(visitor); + + if (!x.getValueExpr().getAttributes().containsKey(EVAL_VALUE)) { + return false; + } + + Object value = x.getValueExpr().getAttribute(EVAL_VALUE); + + for (SQLCaseExpr.Item item : x.getItems()) { + item.getConditionExpr().accept(visitor); + + if (!item.getConditionExpr().getAttributes().containsKey(EVAL_VALUE)) { + return false; + } + + Object conditionValue = item.getConditionExpr().getAttribute(EVAL_VALUE); + + if (_eq(value, conditionValue)) { + item.getValueExpr().accept(visitor); + + if (item.getValueExpr().getAttributes().containsKey(EVAL_VALUE)) { + x.getAttributes().put(EVAL_VALUE, item.getValueExpr().getAttribute(EVAL_VALUE)); + } + + return false; + } + } + + if (x.getElseExpr() != null) { + x.getElseExpr().accept(visitor); + + if (x.getElseExpr().getAttributes().containsKey(EVAL_VALUE)) { + x.getAttributes().put(EVAL_VALUE, x.getElseExpr().getAttribute(EVAL_VALUE)); + } + } + + return false; + } public static boolean visit(SQLEvalVisitor visitor, SQLBinaryOpExpr x) { x.getLeft().accept(visitor); @@ -122,35 +163,35 @@ public class SQLEvalVisitorUtils { Object value = null; switch (x.getOperator()) { case Add: - value = _add(x.getLeft().getAttribute(EVAL_VALUE), x.getRight().getAttributes().get(EVAL_VALUE)); + value = add(x.getLeft().getAttribute(EVAL_VALUE), x.getRight().getAttributes().get(EVAL_VALUE)); x.putAttribute(EVAL_VALUE, value); break; case Subtract: - value = _sub(x.getLeft().getAttribute(EVAL_VALUE), x.getRight().getAttributes().get(EVAL_VALUE)); + value = sub(x.getLeft().getAttribute(EVAL_VALUE), x.getRight().getAttributes().get(EVAL_VALUE)); x.putAttribute(EVAL_VALUE, value); break; case Multiply: - value = _multi(x.getLeft().getAttribute(EVAL_VALUE), x.getRight().getAttributes().get(EVAL_VALUE)); + value = multi(x.getLeft().getAttribute(EVAL_VALUE), x.getRight().getAttributes().get(EVAL_VALUE)); x.putAttribute(EVAL_VALUE, value); break; case Divide: - value = _div(x.getLeft().getAttribute(EVAL_VALUE), x.getRight().getAttributes().get(EVAL_VALUE)); + value = div(x.getLeft().getAttribute(EVAL_VALUE), x.getRight().getAttributes().get(EVAL_VALUE)); x.putAttribute(EVAL_VALUE, value); break; case GreaterThan: - value = _gt(x.getLeft().getAttribute(EVAL_VALUE), x.getRight().getAttributes().get(EVAL_VALUE)); + value = gt(x.getLeft().getAttribute(EVAL_VALUE), x.getRight().getAttributes().get(EVAL_VALUE)); x.putAttribute(EVAL_VALUE, value); break; case GreaterThanOrEqual: - value = _gteq(x.getLeft().getAttribute(EVAL_VALUE), x.getRight().getAttributes().get(EVAL_VALUE)); + value = gteq(x.getLeft().getAttribute(EVAL_VALUE), x.getRight().getAttributes().get(EVAL_VALUE)); x.putAttribute(EVAL_VALUE, value); break; case LessThan: - value = _lt(x.getLeft().getAttribute(EVAL_VALUE), x.getRight().getAttributes().get(EVAL_VALUE)); + value = lt(x.getLeft().getAttribute(EVAL_VALUE), x.getRight().getAttributes().get(EVAL_VALUE)); x.putAttribute(EVAL_VALUE, value); break; case LessThanOrEqual: - value = _lteq(x.getLeft().getAttribute(EVAL_VALUE), x.getRight().getAttributes().get(EVAL_VALUE)); + value = lteq(x.getLeft().getAttribute(EVAL_VALUE), x.getRight().getAttributes().get(EVAL_VALUE)); x.putAttribute(EVAL_VALUE, value); break; default: @@ -160,6 +201,11 @@ public class SQLEvalVisitorUtils { return false; } + public static boolean visit(SQLEvalVisitor visitor, SQLNumericLiteralExpr x) { + x.getAttributes().put(EVAL_VALUE, x.getNumber()); + return false; + } + public static boolean visit(SQLEvalVisitor visitor, SQLVariantRefExpr x) { if (!"?".equals(x.getName())) { return false; @@ -394,7 +440,7 @@ public class SQLEvalVisitorUtils { throw new IllegalArgumentException(); } - public static Object _div(Object a, Object b) { + public static Object div(Object a, Object b) { if (a == null || b == null) { return null; } @@ -426,7 +472,7 @@ public class SQLEvalVisitorUtils { throw new IllegalArgumentException(); } - public static boolean _gt(Object a, Object b) { + public static boolean gt(Object a, Object b) { if (a == null) { return false; } @@ -481,15 +527,15 @@ public class SQLEvalVisitorUtils { throw new IllegalArgumentException(); } - public static boolean _gteq(Object a, Object b) { + public static boolean gteq(Object a, Object b) { if (_eq(a, b)) { return true; } - return _gt(a, b); + return gt(a, b); } - public static boolean _lt(Object a, Object b) { + public static boolean lt(Object a, Object b) { if (a == null) { return true; } @@ -544,12 +590,12 @@ public class SQLEvalVisitorUtils { throw new IllegalArgumentException(); } - public static boolean _lteq(Object a, Object b) { + public static boolean lteq(Object a, Object b) { if (_eq(a, b)) { return true; } - return _lt(a, b); + return lt(a, b); } public static boolean _eq(Object a, Object b) { @@ -607,7 +653,7 @@ public class SQLEvalVisitorUtils { throw new IllegalArgumentException(); } - public static Object _add(Object a, Object b) { + public static Object add(Object a, Object b) { if (a == null) { return b; } @@ -655,7 +701,7 @@ public class SQLEvalVisitorUtils { throw new IllegalArgumentException(); } - public static Object _sub(Object a, Object b) { + public static Object sub(Object a, Object b) { if (a == null) { return null; } @@ -699,7 +745,7 @@ public class SQLEvalVisitorUtils { throw new IllegalArgumentException(); } - public static Object _multi(Object a, Object b) { + public static Object multi(Object a, Object b) { if (a == null || b == null) { return null; } diff --git a/src/main/java/com/alibaba/druid/util/JdbcConstants.java b/src/main/java/com/alibaba/druid/util/JdbcConstants.java new file mode 100644 index 0000000000..d7b2a59cbd --- /dev/null +++ b/src/main/java/com/alibaba/druid/util/JdbcConstants.java @@ -0,0 +1,41 @@ +package com.alibaba.druid.util; + +public interface JdbcConstants { + + public static final String JTDS = "jtds"; + + public static final String MOCK = "mock"; + + public static final String HSQL = "hsql"; + + public static final String DB2 = "db2"; + + public static final String DB2_DRIVER = "COM.ibm.db2.jdbc.app.DB2Driver"; + + public static final String POSTGRESQL = "postgresql"; + + public static final String SYBASE = "sybase"; + + public static final String SQL_SERVER = "sqlserver"; + + public static final String ORACLE = "oracle"; + public static final String ALI_ORACLE = "AliOracle"; + + public static final String ORACLE_DRIVER = "oracle.jdbc.driver.OracleDriver"; + + public static final String ALI_ORACLE_DRIVER = "com.alibaba.jdbc.AlibabaDriver"; + + public static final String MYSQL = "mysql"; + + public static final String MYSQL_DRIVER = "com.mysql.jdbc.Driver"; + + public static final String DERBY = "derby"; + + public static final String HBASE = "hbase"; + + public static final String HIVE = "hive"; + + public static final String H2 = "h2"; + + public static final String H2_DRIVER = "org.h2.Driver"; +} diff --git a/src/main/java/com/alibaba/druid/util/JdbcUtils.java b/src/main/java/com/alibaba/druid/util/JdbcUtils.java index 9d1a9e21b4..8aa458ae1d 100644 --- a/src/main/java/com/alibaba/druid/util/JdbcUtils.java +++ b/src/main/java/com/alibaba/druid/util/JdbcUtils.java @@ -45,44 +45,9 @@ import com.alibaba.druid.support.logging.LogFactory; /** * @author wenshao */ -public final class JdbcUtils { +public final class JdbcUtils implements JdbcConstants { - public static final String JTDS = "jtds"; - - public static final String MOCK = "mock"; - - public static final String HSQL = "hsql"; - - public static final String DB2 = "db2"; - - private static final String DB2_DRIVER = "COM.ibm.db2.jdbc.app.DB2Driver"; - - public static final String POSTGRESQL = "postgresql"; - - public static final String SYBASE = "sybase"; - - public static final String SQL_SERVER = "sqlserver"; - - public static final String ORACLE = "oracle"; - public static final String ALI_ORACLE = "AliOracle"; - - private static final String ORACLE_DRIVER = "oracle.jdbc.driver.OracleDriver"; - - private static final String ALI_ORACLE_DRIVER = "com.alibaba.jdbc.AlibabaDriver"; - - public static final String MYSQL = "mysql"; - - private static final String MYSQL_DRIVER = "com.mysql.jdbc.Driver"; - - public static final String DERBY = "derby"; - - public static final String HBASE = "hbase"; - - public static final String HIVE = "hive"; - - public static final String H2 = "h2"; - - private static final String H2_DRIVER = "org.h2.Driver"; + private final static Log LOG = LogFactory.getLog(JdbcUtils.class); diff --git a/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalCaseThen.java b/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalCaseThen.java new file mode 100644 index 0000000000..61cdecb7e7 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalCaseThen.java @@ -0,0 +1,15 @@ +package com.alibaba.druid.bvt.sql.eval; + +import com.alibaba.druid.sql.visitor.SQLEvalVisitorUtils; +import com.alibaba.druid.util.JdbcConstants; + +import junit.framework.Assert; +import junit.framework.TestCase; + + +public class EvalCaseThen extends TestCase { + public void test_eval_then() throws Exception { + Assert.assertEquals(111, SQLEvalVisitorUtils.evalExpr(JdbcConstants.MYSQL, "case ? when 0 then 111 else 222 end", 0)); + Assert.assertEquals(222, SQLEvalVisitorUtils.evalExpr(JdbcConstants.MYSQL, "case ? when 0 then 111 else 222 end", 1)); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalTest.java b/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalTest.java index f0854173b3..7078418a3f 100644 --- a/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalTest.java +++ b/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalTest.java @@ -15,21 +15,53 @@ */ package com.alibaba.druid.bvt.sql.eval; +import java.math.BigDecimal; + import junit.framework.Assert; import junit.framework.TestCase; import com.alibaba.druid.sql.visitor.SQLEvalVisitorUtils; -import com.alibaba.druid.util.JdbcUtils; +import com.alibaba.druid.util.JdbcConstants; public class EvalTest extends TestCase { public void testEval() throws Exception { - Assert.assertEquals("A", SQLEvalVisitorUtils.evalExpr(JdbcUtils.MYSQL, "?", "A")); - Assert.assertEquals(123, SQLEvalVisitorUtils.evalExpr(JdbcUtils.MYSQL, "?", 123)); + Assert.assertEquals("A", SQLEvalVisitorUtils.evalExpr(JdbcConstants.MYSQL, "?", "A")); + Assert.assertEquals(123, SQLEvalVisitorUtils.evalExpr(JdbcConstants.MYSQL, "?", 123)); } public void testEval_1() throws Exception { - Assert.assertEquals("AB", SQLEvalVisitorUtils.evalExpr(JdbcUtils.MYSQL, "? + ?", "A", "B")); - Assert.assertEquals(234, SQLEvalVisitorUtils.evalExpr(JdbcUtils.MYSQL, "? + ?", 123, 111)); + Assert.assertEquals("AB", SQLEvalVisitorUtils.evalExpr(JdbcConstants.MYSQL, "? + ?", "A", "B")); + Assert.assertEquals(234, SQLEvalVisitorUtils.evalExpr(JdbcConstants.MYSQL, "? + ?", 123, 111)); + } + + public void testEval_2() throws Exception { + Assert.assertEquals(110, SQLEvalVisitorUtils.evalExpr(JdbcConstants.MYSQL, "? * ?", 10, 11)); + } + + public void testEval_3() throws Exception { + Assert.assertEquals(new BigDecimal("110"), SQLEvalVisitorUtils.evalExpr(JdbcConstants.MYSQL, "? * ?", + new BigDecimal("10"), + new BigDecimal("11"))); + } + + public void testEval_4() throws Exception { + Assert.assertEquals(new BigDecimal("110"), + SQLEvalVisitorUtils.evalExpr(JdbcConstants.MYSQL, "? * 11", new BigDecimal("10"))); + } + + public void testEval_5() throws Exception { + Assert.assertEquals(new BigDecimal("110.0"), + SQLEvalVisitorUtils.evalExpr(JdbcConstants.MYSQL, "? * 11.0", new BigDecimal("10"))); + } + + public void testEval_6() throws Exception { + Assert.assertEquals(new BigDecimal("110.0"), + SQLEvalVisitorUtils.evalExpr(JdbcConstants.MYSQL, "? * 11", new BigDecimal("10.0"))); + } + + public void testEval_7() throws Exception { + Assert.assertEquals(new BigDecimal("110.0"), + SQLEvalVisitorUtils.evalExpr(JdbcConstants.MYSQL, "? * 11.0", "10")); } }