From 70994c3e3c57580a7306af896527e19a543c0af5 Mon Sep 17 00:00:00 2001 From: Min Zhou Date: Fri, 25 Jan 2013 12:55:18 +0800 Subject: [PATCH 01/15] Equality operator '=' is missed in eval visitor utils --- .../java/com/alibaba/druid/sql/visitor/SQLEvalVisitorUtils.java | 1 + 1 file changed, 1 insertion(+) 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 6e50fb87e0..e75dcc5e70 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SQLEvalVisitorUtils.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SQLEvalVisitorUtils.java @@ -827,6 +827,7 @@ public class SQLEvalVisitorUtils { x.putAttribute(EVAL_VALUE, value); break; case Is: + case Equality: value = eq(left.getAttribute(EVAL_VALUE), right.getAttributes().get(EVAL_VALUE)); x.putAttribute(EVAL_VALUE, value); break; From 9cd061eb5ec604b55973c91b04c1dff80201e74f Mon Sep 17 00:00:00 2001 From: wenshao Date: Sat, 26 Jan 2013 00:31:20 +0800 Subject: [PATCH 02/15] SQL Eval support like & not like --- .../sql/visitor/SQLEvalVisitorUtils.java | 280 +++++++++++------- .../druid/bvt/sql/eval/EvalLikeTest.java | 19 ++ .../alibaba/druid/bvt/sql/eval/LikeTest.java | 58 ++++ 3 files changed, 258 insertions(+), 99 deletions(-) create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/eval/EvalLikeTest.java create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/eval/LikeTest.java 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 e75dcc5e70..34d1442384 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SQLEvalVisitorUtils.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SQLEvalVisitorUtils.java @@ -189,7 +189,7 @@ public class SQLEvalVisitorUtils { } String strValue = param0Value.toString(); - int intValue = _int(param1Value); + int intValue = castToInteger(param1Value); String result = strValue.substring(0, intValue); @@ -211,7 +211,7 @@ public class SQLEvalVisitorUtils { } String strValue = param0Value.toString(); - int intValue = _int(param1Value); + int intValue = castToInteger(param1Value); String result = strValue.substring(strValue.length() - intValue, strValue.length()); @@ -326,8 +326,8 @@ public class SQLEvalVisitorUtils { return false; } - int intValue0 = _int(param0Value); - int intValue1 = _int(param1Value); + int intValue0 = castToInteger(param0Value); + int intValue1 = castToInteger(param1Value); int result = intValue0 % intValue1; @@ -351,7 +351,7 @@ public class SQLEvalVisitorUtils { } else if (paramValue instanceof Long) { result = Math.abs(((Long) paramValue).longValue()); } else { - result = _decimal(paramValue).abs(); + result = castToDecimal(paramValue).abs(); } x.putAttribute(EVAL_VALUE, result); @@ -368,7 +368,7 @@ public class SQLEvalVisitorUtils { return false; } - double doubleValue = _double(paramValue); + double doubleValue = castToDouble(paramValue); double result = Math.acos(doubleValue); if (Double.isNaN(result)) { @@ -389,7 +389,7 @@ public class SQLEvalVisitorUtils { return false; } - double doubleValue = _double(paramValue); + double doubleValue = castToDouble(paramValue); double result = Math.asin(doubleValue); if (Double.isNaN(result)) { @@ -410,7 +410,7 @@ public class SQLEvalVisitorUtils { return false; } - double doubleValue = _double(paramValue); + double doubleValue = castToDouble(paramValue); double result = Math.atan(doubleValue); if (Double.isNaN(result)) { @@ -434,8 +434,8 @@ public class SQLEvalVisitorUtils { return false; } - double doubleValue0 = _double(param0Value); - double doubleValue1 = _double(param1Value); + double doubleValue0 = castToDouble(param0Value); + double doubleValue1 = castToDouble(param1Value); double result = Math.atan2(doubleValue0, doubleValue1); if (Double.isNaN(result)) { @@ -456,7 +456,7 @@ public class SQLEvalVisitorUtils { return false; } - double doubleValue = _double(paramValue); + double doubleValue = castToDouble(paramValue); int result = (int) Math.ceil(doubleValue); if (Double.isNaN(result)) { @@ -477,7 +477,7 @@ public class SQLEvalVisitorUtils { return false; } - double doubleValue = _double(paramValue); + double doubleValue = castToDouble(paramValue); int result = (int) Math.cos(doubleValue); if (Double.isNaN(result)) { @@ -498,7 +498,7 @@ public class SQLEvalVisitorUtils { return false; } - double doubleValue = _double(paramValue); + double doubleValue = castToDouble(paramValue); int result = (int) Math.sin(doubleValue); if (Double.isNaN(result)) { @@ -519,7 +519,7 @@ public class SQLEvalVisitorUtils { return false; } - double doubleValue = _double(paramValue); + double doubleValue = castToDouble(paramValue); int result = (int) Math.log(doubleValue); if (Double.isNaN(result)) { @@ -540,7 +540,7 @@ public class SQLEvalVisitorUtils { return false; } - double doubleValue = _double(paramValue); + double doubleValue = castToDouble(paramValue); int result = (int) Math.log10(doubleValue); if (Double.isNaN(result)) { @@ -561,7 +561,7 @@ public class SQLEvalVisitorUtils { return false; } - double doubleValue = _double(paramValue); + double doubleValue = castToDouble(paramValue); int result = (int) Math.tan(doubleValue); if (Double.isNaN(result)) { @@ -582,7 +582,7 @@ public class SQLEvalVisitorUtils { return false; } - double doubleValue = _double(paramValue); + double doubleValue = castToDouble(paramValue); int result = (int) Math.sqrt(doubleValue); if (Double.isNaN(result)) { @@ -606,8 +606,8 @@ public class SQLEvalVisitorUtils { return false; } - double doubleValue0 = _double(param0Value); - double doubleValue1 = _double(param1Value); + double doubleValue0 = castToDouble(param0Value); + double doubleValue1 = castToDouble(param1Value); double result = Math.pow(doubleValue0, doubleValue1); if (Double.isNaN(result)) { @@ -678,7 +678,7 @@ public class SQLEvalVisitorUtils { if (!x.getValueExpr().getAttributes().containsKey(EVAL_VALUE)) { return false; } - + value = x.getValueExpr().getAttribute(EVAL_VALUE); } else { value = null; @@ -837,18 +837,31 @@ public class SQLEvalVisitorUtils { break; case RegExp: case RLike: { - String pattern = _string(right.getAttributes().get(EVAL_VALUE)); - String input = _string(left.getAttributes().get(EVAL_VALUE)); + String pattern = castToString(right.getAttributes().get(EVAL_VALUE)); + String input = castToString(left.getAttributes().get(EVAL_VALUE)); boolean matchResult = Pattern.matches(pattern, input); x.putAttribute(EVAL_VALUE, matchResult); } break; case NotRegExp: case NotRLike: { - String pattern = _string(right.getAttributes().get(EVAL_VALUE)); - String input = _string(left.getAttributes().get(EVAL_VALUE)); + String pattern = castToString(right.getAttributes().get(EVAL_VALUE)); + String input = castToString(left.getAttributes().get(EVAL_VALUE)); boolean matchResult = !Pattern.matches(pattern, input); x.putAttribute(EVAL_VALUE, matchResult); + } + case Like: { + String pattern = castToString(right.getAttributes().get(EVAL_VALUE)); + String input = castToString(left.getAttributes().get(EVAL_VALUE)); + boolean matchResult = like(input, pattern); + x.putAttribute(EVAL_VALUE, matchResult); + } + break; + case NotLike: { + String pattern = castToString(right.getAttributes().get(EVAL_VALUE)); + String input = castToString(left.getAttributes().get(EVAL_VALUE)); + boolean matchResult = !like(input, pattern); + x.putAttribute(EVAL_VALUE, matchResult); } break; default: @@ -883,7 +896,7 @@ public class SQLEvalVisitorUtils { return false; } - public static Boolean _bool(Object val) { + public static Boolean castToBoolean(Object val) { if (val == null) { return null; } @@ -899,7 +912,7 @@ public class SQLEvalVisitorUtils { throw new IllegalArgumentException(); } - public static String _string(Object val) { + public static String castToString(Object val) { Object value = val; if (value == null) { @@ -909,7 +922,7 @@ public class SQLEvalVisitorUtils { return value.toString(); } - public static Byte _byte(Object val) { + public static Byte castToByte(Object val) { if (val == null) { return null; } @@ -921,7 +934,7 @@ public class SQLEvalVisitorUtils { return ((Number) val).byteValue(); } - public static Short _short(Object val) { + public static Short castToShort(Object val) { if (val == null) { return null; } @@ -933,7 +946,7 @@ public class SQLEvalVisitorUtils { return ((Number) val).shortValue(); } - public static Integer _int(Object val) { + public static Integer castToInteger(Object val) { if (val == null) { return null; } @@ -945,7 +958,7 @@ public class SQLEvalVisitorUtils { return ((Number) val).intValue(); } - public static Long _long(Object val) { + public static Long castToLong(Object val) { if (val == null) { return null; } @@ -957,7 +970,7 @@ public class SQLEvalVisitorUtils { return ((Number) val).longValue(); } - public static Float _float(Object val) { + public static Float castToFloat(Object val) { if (val == null) { return null; } @@ -969,7 +982,7 @@ public class SQLEvalVisitorUtils { return ((Number) val).floatValue(); } - public static Double _double(Object val) { + public static Double castToDouble(Object val) { if (val == null) { return null; } @@ -981,7 +994,7 @@ public class SQLEvalVisitorUtils { return ((Number) val).doubleValue(); } - public static BigInteger _bigInt(Object val) { + public static BigInteger castToBigInteger(Object val) { if (val == null) { return null; } @@ -997,7 +1010,7 @@ public class SQLEvalVisitorUtils { return BigInteger.valueOf(((Number) val).longValue()); } - public static Date _date(Object val) { + public static Date castToDate(Object val) { if (val == null) { return null; } @@ -1011,13 +1024,13 @@ public class SQLEvalVisitorUtils { } if (val instanceof String) { - return _date((String) val); + return castToDate((String) val); } throw new DruidRuntimeException("can cast to date"); } - public static Date _date(String text) { + public static Date castToDate(String text) { if (text == null || text.length() == 0) { return null; } @@ -1037,7 +1050,7 @@ public class SQLEvalVisitorUtils { } } - public static BigDecimal _decimal(Object val) { + public static BigDecimal castToDecimal(Object val) { if (val == null) { return null; } @@ -1061,7 +1074,7 @@ public class SQLEvalVisitorUtils { return BigDecimal.valueOf(((Number) val).longValue()); } - public static Object _sum(Object a, Object b) { + public static Object sum(Object a, Object b) { if (a == null) { return b; } @@ -1071,27 +1084,27 @@ public class SQLEvalVisitorUtils { } if (a instanceof BigDecimal || b instanceof BigDecimal) { - return _decimal(a).add(_decimal(b)); + return castToDecimal(a).add(castToDecimal(b)); } if (a instanceof BigInteger || b instanceof BigInteger) { - return _bigInt(a).add(_bigInt(b)); + return castToBigInteger(a).add(castToBigInteger(b)); } if (a instanceof Long || b instanceof Long) { - return _long(a) + _long(b); + return castToLong(a) + castToLong(b); } if (a instanceof Integer || b instanceof Integer) { - return _int(a) + _int(b); + return castToInteger(a) + castToInteger(b); } if (a instanceof Short || b instanceof Short) { - return _short(a) + _short(b); + return castToShort(a) + castToShort(b); } if (a instanceof Byte || b instanceof Byte) { - return _byte(a) + _byte(b); + return castToByte(a) + castToByte(b); } throw new IllegalArgumentException(); @@ -1103,27 +1116,27 @@ public class SQLEvalVisitorUtils { } if (a instanceof BigDecimal || b instanceof BigDecimal) { - return _decimal(a).divide(_decimal(b)); + return castToDecimal(a).divide(castToDecimal(b)); } if (a instanceof BigInteger || b instanceof BigInteger) { - return _bigInt(a).divide(_bigInt(b)); + return castToBigInteger(a).divide(castToBigInteger(b)); } if (a instanceof Long || b instanceof Long) { - return _long(a) / _long(b); + return castToLong(a) / castToLong(b); } if (a instanceof Integer || b instanceof Integer) { - return _int(a) / _int(b); + return castToInteger(a) / castToInteger(b); } if (a instanceof Short || b instanceof Short) { - return _short(a) / _short(b); + return castToShort(a) / castToShort(b); } if (a instanceof Byte || b instanceof Byte) { - return _byte(a) / _byte(b); + return castToByte(a) / castToByte(b); } throw new IllegalArgumentException(); @@ -1139,32 +1152,32 @@ public class SQLEvalVisitorUtils { } if (a instanceof BigDecimal || b instanceof BigDecimal) { - return _decimal(a).compareTo(_decimal(b)) > 0; + return castToDecimal(a).compareTo(castToDecimal(b)) > 0; } if (a instanceof BigInteger || b instanceof BigInteger) { - return _bigInt(a).compareTo(_bigInt(b)) > 0; + return castToBigInteger(a).compareTo(castToBigInteger(b)) > 0; } if (a instanceof Long || b instanceof Long) { - return _long(a) > _long(b); + return castToLong(a) > castToLong(b); } if (a instanceof Integer || b instanceof Integer) { - return _int(a) > _int(b); + return castToInteger(a) > castToInteger(b); } if (a instanceof Short || b instanceof Short) { - return _short(a) > _short(b); + return castToShort(a) > castToShort(b); } if (a instanceof Byte || b instanceof Byte) { - return _byte(a) > _byte(b); + return castToByte(a) > castToByte(b); } if (a instanceof Date || b instanceof Date) { - Date d1 = _date(a); - Date d2 = _date(b); + Date d1 = castToDate(a); + Date d2 = castToDate(b); if (d1 == d2) { return false; @@ -1202,32 +1215,32 @@ public class SQLEvalVisitorUtils { } if (a instanceof BigDecimal || b instanceof BigDecimal) { - return _decimal(a).compareTo(_decimal(b)) < 0; + return castToDecimal(a).compareTo(castToDecimal(b)) < 0; } if (a instanceof BigInteger || b instanceof BigInteger) { - return _bigInt(a).compareTo(_bigInt(b)) < 0; + return castToBigInteger(a).compareTo(castToBigInteger(b)) < 0; } if (a instanceof Long || b instanceof Long) { - return _long(a) < _long(b); + return castToLong(a) < castToLong(b); } if (a instanceof Integer || b instanceof Integer) { - return _int(a) < _int(b); + return castToInteger(a) < castToInteger(b); } if (a instanceof Short || b instanceof Short) { - return _short(a) < _short(b); + return castToShort(a) < castToShort(b); } if (a instanceof Byte || b instanceof Byte) { - return _byte(a) < _byte(b); + return castToByte(a) < castToByte(b); } if (a instanceof Date || b instanceof Date) { - Date d1 = _date(a); - Date d2 = _date(b); + Date d1 = castToDate(a); + Date d2 = castToDate(b); if (d1 == d2) { return false; @@ -1269,32 +1282,32 @@ public class SQLEvalVisitorUtils { } if (a instanceof BigDecimal || b instanceof BigDecimal) { - return _decimal(a).compareTo(_decimal(b)) == 0; + return castToDecimal(a).compareTo(castToDecimal(b)) == 0; } if (a instanceof BigInteger || b instanceof BigInteger) { - return _bigInt(a).compareTo(_bigInt(b)) == 0; + return castToBigInteger(a).compareTo(castToBigInteger(b)) == 0; } if (a instanceof Long || b instanceof Long) { - return _long(a) == _long(b); + return castToLong(a) == castToLong(b); } if (a instanceof Integer || b instanceof Integer) { - return _int(a) == _int(b); + return castToInteger(a) == castToInteger(b); } if (a instanceof Short || b instanceof Short) { - return _short(a) == _short(b); + return castToShort(a) == castToShort(b); } if (a instanceof Byte || b instanceof Byte) { - return _byte(a) == _byte(b); + return castToByte(a) == castToByte(b); } if (a instanceof Date || b instanceof Date) { - Date d1 = _date(a); - Date d2 = _date(b); + Date d1 = castToDate(a); + Date d2 = castToDate(b); if (d1 == d2) { return true; @@ -1306,9 +1319,9 @@ public class SQLEvalVisitorUtils { return d1.equals(d2); } - + if (a instanceof String || b instanceof String) { - return _string(a).equals(_string(b)); + return castToString(a).equals(castToString(b)); } throw new IllegalArgumentException(); @@ -1324,39 +1337,39 @@ public class SQLEvalVisitorUtils { } if (a instanceof BigDecimal || b instanceof BigDecimal) { - return _decimal(a).add(_decimal(b)); + return castToDecimal(a).add(castToDecimal(b)); } if (a instanceof BigInteger || b instanceof BigInteger) { - return _bigInt(a).add(_bigInt(b)); + return castToBigInteger(a).add(castToBigInteger(b)); } if (a instanceof Double || b instanceof Double) { - return _double(a) + _double(b); + return castToDouble(a) + castToDouble(b); } if (a instanceof Float || b instanceof Float) { - return _float(a) + _float(b); + return castToFloat(a) + castToFloat(b); } if (a instanceof Long || b instanceof Long) { - return _long(a) + _long(b); + return castToLong(a) + castToLong(b); } if (a instanceof Integer || b instanceof Integer) { - return _int(a) + _int(b); + return castToInteger(a) + castToInteger(b); } if (a instanceof Short || b instanceof Short) { - return _short(a) + _short(b); + return castToShort(a) + castToShort(b); } if (a instanceof Byte || b instanceof Byte) { - return _byte(a) + _byte(b); + return castToByte(a) + castToByte(b); } if (a instanceof String || b instanceof String) { - return _string(a) + _string(b); + return castToString(a) + castToString(b); } throw new IllegalArgumentException(); @@ -1372,35 +1385,35 @@ public class SQLEvalVisitorUtils { } if (a instanceof BigDecimal || b instanceof BigDecimal) { - return _decimal(a).subtract(_decimal(b)); + return castToDecimal(a).subtract(castToDecimal(b)); } if (a instanceof BigInteger || b instanceof BigInteger) { - return _bigInt(a).subtract(_bigInt(b)); + return castToBigInteger(a).subtract(castToBigInteger(b)); } if (a instanceof Double || b instanceof Double) { - return _double(a) - _double(b); + return castToDouble(a) - castToDouble(b); } if (a instanceof Float || b instanceof Float) { - return _float(a) - _float(b); + return castToFloat(a) - castToFloat(b); } if (a instanceof Long || b instanceof Long) { - return _long(a) - _long(b); + return castToLong(a) - castToLong(b); } if (a instanceof Integer || b instanceof Integer) { - return _int(a) - _int(b); + return castToInteger(a) - castToInteger(b); } if (a instanceof Short || b instanceof Short) { - return _short(a) - _short(b); + return castToShort(a) - castToShort(b); } if (a instanceof Byte || b instanceof Byte) { - return _byte(a) - _byte(b); + return castToByte(a) - castToByte(b); } throw new IllegalArgumentException(); @@ -1412,29 +1425,98 @@ public class SQLEvalVisitorUtils { } if (a instanceof BigDecimal || b instanceof BigDecimal) { - return _decimal(a).multiply(_decimal(b)); + return castToDecimal(a).multiply(castToDecimal(b)); } if (a instanceof BigInteger || b instanceof BigInteger) { - return _bigInt(a).multiply(_bigInt(b)); + return castToBigInteger(a).multiply(castToBigInteger(b)); } if (a instanceof Long || b instanceof Long) { - return _long(a) * _long(b); + return castToLong(a) * castToLong(b); } if (a instanceof Integer || b instanceof Integer) { - return _int(a) * _int(b); + return castToInteger(a) * castToInteger(b); } if (a instanceof Short || b instanceof Short) { - return _short(a) * _short(b); + return castToShort(a) * castToShort(b); } if (a instanceof Byte || b instanceof Byte) { - return _byte(a) * _byte(b); + return castToByte(a) * castToByte(b); } throw new IllegalArgumentException(); } + + public static boolean like(String input, String pattern) { + if (pattern == null) { + throw new IllegalArgumentException("pattern is null"); + } + + StringBuilder regexprBuilder = new StringBuilder(pattern.length() + 4); + + final int STAT_NOTSET = 0; + final int STAT_RANGE = 1; + final int STAT_LITERAL = 2; + + int stat = STAT_NOTSET; + + int blockStart = -1; + for (int i = 0; i < pattern.length(); ++i) { + char ch = pattern.charAt(i); + + if (stat == STAT_LITERAL // + && (ch == '%' || ch == '_' || ch == '[')) { + String block = pattern.substring(blockStart, i); + regexprBuilder.append("\\Q"); + regexprBuilder.append(block); + regexprBuilder.append("\\E"); + blockStart = -1; + stat = STAT_NOTSET; + } + + if (ch == '%') { + regexprBuilder.append(".*"); + } else if (ch == '_') { + regexprBuilder.append('.'); + } else if (ch == '[') { + if (stat == STAT_RANGE) { + throw new IllegalArgumentException("illegal pattern : " + pattern); + } + stat = STAT_RANGE; + blockStart = i; + } else if (ch == ']') { + if (stat != STAT_RANGE) { + throw new IllegalArgumentException("illegal pattern : " + pattern); + } + String block = pattern.substring(blockStart, i + 1); + regexprBuilder.append(block); + + blockStart = -1; + } else { + if (stat == STAT_NOTSET) { + stat = STAT_LITERAL; + blockStart = i; + } + + if (stat == STAT_LITERAL && i == pattern.length() - 1) { + String block = pattern.substring(blockStart, i + 1); + regexprBuilder.append("\\Q"); + regexprBuilder.append(block); + regexprBuilder.append("\\E"); + } + } + } + if ("%".equals(pattern) || "%%".equals(pattern)) { + return true; + } + // %xxxx + + String regexpr = regexprBuilder.toString(); + return Pattern.matches(regexpr, input); + } + } diff --git a/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalLikeTest.java b/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalLikeTest.java new file mode 100644 index 0000000000..cfeeee3f63 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalLikeTest.java @@ -0,0 +1,19 @@ +package com.alibaba.druid.bvt.sql.eval; + +import junit.framework.TestCase; + +import org.junit.Assert; + +import com.alibaba.druid.sql.visitor.SQLEvalVisitorUtils; +import com.alibaba.druid.util.JdbcConstants; + + +public class EvalLikeTest extends TestCase { + public void test_like() throws Exception { + Assert.assertEquals(true, SQLEvalVisitorUtils.evalExpr(JdbcConstants.MYSQL, "'a' LIKE '[a-d]'")); + } + + public void test_not_like() throws Exception { + Assert.assertEquals(false, SQLEvalVisitorUtils.evalExpr(JdbcConstants.MYSQL, "'a' NOT LIKE '[a-d]'")); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/eval/LikeTest.java b/src/test/java/com/alibaba/druid/bvt/sql/eval/LikeTest.java new file mode 100644 index 0000000000..15df766806 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/eval/LikeTest.java @@ -0,0 +1,58 @@ +package com.alibaba.druid.bvt.sql.eval; + +import junit.framework.TestCase; + +import org.junit.Assert; + +import com.alibaba.druid.sql.visitor.SQLEvalVisitorUtils; + +public class LikeTest extends TestCase { + + public void test_any_0() throws Exception { + Assert.assertTrue(SQLEvalVisitorUtils.like("abcdefg", "%")); + } + + public void test_any_1() throws Exception { + Assert.assertTrue(SQLEvalVisitorUtils.like("abcdefg", "%%")); + } + + public void test_any_2() throws Exception { + Assert.assertTrue(SQLEvalVisitorUtils.like("abcdefg", "%b%")); + } + + public void test_any_3() throws Exception { + Assert.assertTrue(SQLEvalVisitorUtils.like("abcdefg", "a%")); + } + + public void test_any_4() throws Exception { + Assert.assertTrue(SQLEvalVisitorUtils.like("abcdefg", "%g")); + } + + public void test_single_0() throws Exception { + Assert.assertTrue(SQLEvalVisitorUtils.like("a", "_")); + } + + public void test_single_1() throws Exception { + Assert.assertTrue(SQLEvalVisitorUtils.like("ab", "__")); + } + + public void test_single_2() throws Exception { + Assert.assertTrue(SQLEvalVisitorUtils.like("abcd", "a__d")); + } + + public void test_single_3() throws Exception { + Assert.assertTrue(SQLEvalVisitorUtils.like("abcdf", "a__d_")); + } + + public void test_range_0() throws Exception { + Assert.assertTrue(SQLEvalVisitorUtils.like("abcdf", "abcd[a-f]")); + } + + public void test_range_1() throws Exception { + Assert.assertFalse(SQLEvalVisitorUtils.like("abcdf", "abcd[a-e]")); + } + + public void test_range_2() throws Exception { + Assert.assertTrue(SQLEvalVisitorUtils.like("ab", "a[abf]")); + } +} From 2bba9fb0e84b0e8eb9907cf6d747e1fd29baebe0 Mon Sep 17 00:00:00 2001 From: wenshao Date: Sat, 26 Jan 2013 00:48:08 +0800 Subject: [PATCH 03/15] SQL Eval support like & not like --- .../java/com/alibaba/druid/sql/visitor/SQLEvalVisitorUtils.java | 1 + 1 file changed, 1 insertion(+) 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 34d1442384..0253cd6f14 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SQLEvalVisitorUtils.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SQLEvalVisitorUtils.java @@ -850,6 +850,7 @@ public class SQLEvalVisitorUtils { boolean matchResult = !Pattern.matches(pattern, input); x.putAttribute(EVAL_VALUE, matchResult); } + break; case Like: { String pattern = castToString(right.getAttributes().get(EVAL_VALUE)); String input = castToString(left.getAttributes().get(EVAL_VALUE)); From 2181750cfea726508f455127ced1d7080e23884e Mon Sep 17 00:00:00 2001 From: wenshao Date: Sat, 26 Jan 2013 01:27:12 +0800 Subject: [PATCH 04/15] SQL Eval support like & not like --- .../java/com/alibaba/druid/sql/visitor/SQLEvalVisitorUtils.java | 1 - 1 file changed, 1 deletion(-) 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 0253cd6f14..af79de83f7 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SQLEvalVisitorUtils.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SQLEvalVisitorUtils.java @@ -1514,7 +1514,6 @@ public class SQLEvalVisitorUtils { if ("%".equals(pattern) || "%%".equals(pattern)) { return true; } - // %xxxx String regexpr = regexprBuilder.toString(); return Pattern.matches(regexpr, input); From 3b9cc87d3c3b45362f1598a1755a25727562948e Mon Sep 17 00:00:00 2001 From: wenshao Date: Sat, 26 Jan 2013 12:34:21 +0800 Subject: [PATCH 05/15] fixed compile warnnings --- .../druid/sql/dialect/mysql/parser/MySqlCreateTableParser.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlCreateTableParser.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlCreateTableParser.java index dca00f4921..461baf6788 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlCreateTableParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlCreateTableParser.java @@ -180,7 +180,6 @@ public class MySqlCreateTableParser extends SQLCreateTableParser { return stmt; } - @SuppressWarnings("unused") protected SQLTableConstaint parseConstraint() { SQLName name = null; if (lexer.token() == (Token.CONSTRAINT)) { From 514672c9fed375a0b0586350d996c7d802af8423 Mon Sep 17 00:00:00 2001 From: Zhanming Qi Date: Tue, 29 Jan 2013 13:51:54 +0800 Subject: [PATCH 06/15] =?UTF-8?q?=E5=B0=8Fbug,=E6=9B=B4=E6=94=B9datasource?= =?UTF-8?q?Id=E4=B8=BAdataSourceId,=E5=8F=AF=E4=BB=A5=E6=8C=89dataSourceId?= =?UTF-8?q?=E5=88=86=E5=88=AB=E6=9F=A5=E7=9C=8BSQL?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/support/http/resources/datasource.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/support/http/resources/datasource.html b/src/main/resources/support/http/resources/datasource.html index 28f7b2908e..33d90dd858 100644 --- a/src/main/resources/support/http/resources/datasource.html +++ b/src/main/resources/support/http/resources/datasource.html @@ -118,7 +118,7 @@ html += 'PollingConnection InfoViewInfo for polling connection. [View JSON API]' - html += 'SQL ListSQL ListViewInfo for SQL. [View JSON API]' html += ''; From f83f076200cc8356928438d36dc16e00b3cc3d7e Mon Sep 17 00:00:00 2001 From: wenshao Date: Sat, 2 Feb 2013 12:38:30 +0800 Subject: [PATCH 07/15] support PaggerUtils --- .../com/alibaba/druid/sql/PagerUtils.java | 134 ++++++++++++++++++ .../druid/sql/ast/statement/SQLSelect.java | 4 + src/test/java/PagerUtils/PagerUtilsTest0.java | 44 ++++++ 3 files changed, 182 insertions(+) create mode 100644 src/main/java/com/alibaba/druid/sql/PagerUtils.java create mode 100644 src/test/java/PagerUtils/PagerUtilsTest0.java diff --git a/src/main/java/com/alibaba/druid/sql/PagerUtils.java b/src/main/java/com/alibaba/druid/sql/PagerUtils.java new file mode 100644 index 0000000000..f576a30b37 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/PagerUtils.java @@ -0,0 +1,134 @@ +package com.alibaba.druid.sql; + +import java.util.List; + +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.ast.expr.SQLAggregateExpr; +import com.alibaba.druid.sql.ast.expr.SQLAllColumnExpr; +import com.alibaba.druid.sql.ast.statement.SQLSelect; +import com.alibaba.druid.sql.ast.statement.SQLSelectItem; +import com.alibaba.druid.sql.ast.statement.SQLSelectQuery; +import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock; +import com.alibaba.druid.sql.ast.statement.SQLSelectStatement; +import com.alibaba.druid.sql.ast.statement.SQLSubqueryTableSource; +import com.alibaba.druid.sql.ast.statement.SQLUnionQuery; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock; +import com.alibaba.druid.sql.dialect.oracle.ast.expr.OracleAggregateExpr; +import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelectQueryBlock; +import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGSelectQueryBlock; +import com.alibaba.druid.sql.dialect.sqlserver.ast.SQLServerSelectQueryBlock; +import com.alibaba.druid.util.JdbcConstants; + +public class PagerUtils { + + public static String count(String sql, String dbType) { + List stmtList = SQLUtils.parseStatements(sql, dbType); + + if (stmtList.size() != 1) { + throw new IllegalArgumentException("sql not support count : " + sql); + } + + SQLStatement stmt = stmtList.get(0); + + if (!(stmt instanceof SQLSelectStatement)) { + throw new IllegalArgumentException("sql not support count : " + sql); + } + + SQLSelectStatement selectStmt = (SQLSelectStatement) stmt; + + return count(selectStmt, dbType); + } + + private static String count(SQLSelectStatement stmt, String dbType) { + SQLSelect select = stmt.getSelect(); + if (select.getOrderBy() != null) { + select.setOrderBy(null); + } + SQLSelectQuery query = select.getQuery(); + clearOrderBy(query); + + if (query instanceof SQLSelectQueryBlock) { + SQLSelectItem countItem = createCountItem(dbType); + + SQLSelectQueryBlock queryBlock = (SQLSelectQueryBlock) query; + queryBlock.getSelectList().clear(); + queryBlock.getSelectList().add(countItem); + return SQLUtils.toSQLString(stmt, dbType); + } else if (query instanceof SQLUnionQuery) { + SQLSelectQueryBlock countSelectQuery = createQueryBlock(dbType); + + SQLSelectItem countItem = createCountItem(dbType); + countSelectQuery.getSelectList().add(countItem); + + countSelectQuery.setFrom(new SQLSubqueryTableSource(select)); + + SQLSelect countSelect = new SQLSelect(countSelectQuery); + SQLSelectStatement countStmt = new SQLSelectStatement(countSelect); + + return SQLUtils.toSQLString(countStmt, dbType); + } + + throw new IllegalStateException(); + } + + private static SQLSelectQueryBlock createQueryBlock(String dbType) { + if (JdbcConstants.MYSQL.equals(dbType)) { + return new MySqlSelectQueryBlock(); + } + + if (JdbcConstants.ORACLE.equals(dbType)) { + return new OracleSelectQueryBlock(); + } + + if (JdbcConstants.POSTGRESQL.equals(dbType)) { + return new PGSelectQueryBlock(); + } + + if (JdbcConstants.SQL_SERVER.equals(dbType)) { + return new SQLServerSelectQueryBlock(); + } + + return new SQLSelectQueryBlock(); + } + + private static SQLSelectItem createCountItem(String dbType) { + SQLAggregateExpr countExpr; + + if (JdbcConstants.ORACLE.equals(dbType)) { + countExpr = new OracleAggregateExpr("COUNT"); + } else { + countExpr = new SQLAggregateExpr("COUNT"); + } + countExpr.getArguments().add(new SQLAllColumnExpr()); + + SQLSelectItem countItem = new SQLSelectItem(countExpr); + return countItem; + } + + private static void clearOrderBy(SQLSelectQuery query) { + if (query instanceof SQLSelectQueryBlock) { + SQLSelectQueryBlock queryBlock = (SQLSelectQueryBlock) query; + if (queryBlock instanceof MySqlSelectQueryBlock) { + MySqlSelectQueryBlock mysqlQueryBlock = (MySqlSelectQueryBlock) queryBlock; + if (mysqlQueryBlock.getOrderBy() != null) { + mysqlQueryBlock.setOrderBy(null); + } + } else if (queryBlock instanceof PGSelectQueryBlock) { + PGSelectQueryBlock pgQueryBlock = (PGSelectQueryBlock) queryBlock; + if (pgQueryBlock.getOrderBy() != null) { + pgQueryBlock.setOrderBy(null); + } + } + return; + } + + if (query instanceof SQLUnionQuery) { + SQLUnionQuery union = (SQLUnionQuery) query; + if (union.getOrderBy() != null) { + union.setOrderBy(null); + } + clearOrderBy(union.getLeft()); + clearOrderBy(union.getRight()); + } + } +} diff --git a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelect.java b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelect.java index db599dcd1e..2c424b7509 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelect.java +++ b/src/main/java/com/alibaba/druid/sql/ast/statement/SQLSelect.java @@ -30,6 +30,10 @@ public class SQLSelect extends SQLObjectImpl { public SQLSelect(){ } + + public SQLSelect(SQLSelectQuery query) { + this.query = query; + } public SQLWithSubqueryClause getWithSubQuery() { return withSubQuery; diff --git a/src/test/java/PagerUtils/PagerUtilsTest0.java b/src/test/java/PagerUtils/PagerUtilsTest0.java new file mode 100644 index 0000000000..0cff3af24a --- /dev/null +++ b/src/test/java/PagerUtils/PagerUtilsTest0.java @@ -0,0 +1,44 @@ +package PagerUtils; + +import junit.framework.TestCase; + +import org.junit.Assert; + +import com.alibaba.druid.sql.PagerUtils; +import com.alibaba.druid.util.JdbcConstants; + +public class PagerUtilsTest0 extends TestCase { + + public void test_mysql_0() throws Exception { + String sql = "select * from t"; + String result = PagerUtils.count(sql, JdbcConstants.MYSQL); + Assert.assertEquals("SELECT COUNT(*)\n" + // + "FROM t", result); + } + + public void test_mysql_1() throws Exception { + String sql = "select id, name from t"; + String result = PagerUtils.count(sql, JdbcConstants.MYSQL); + Assert.assertEquals("SELECT COUNT(*)\n" + // + "FROM t", result); + } + + public void test_mysql_2() throws Exception { + String sql = "select id, name from t order by id"; + String result = PagerUtils.count(sql, JdbcConstants.MYSQL); + Assert.assertEquals("SELECT COUNT(*)\n" + // + "FROM t", result); + } + + public void test_mysql_3() throws Exception { + String sql = "select id, name from t1 union select id, name from t2 order by id"; + String result = PagerUtils.count(sql, JdbcConstants.MYSQL); + Assert.assertEquals("SELECT COUNT(*)\n" + // + "FROM (SELECT id, name" + // + "\n\tFROM t1" + // + "\n\tUNION" + // + "\n\tSELECT id, name" + // + "\n\tFROM t2" + // + "\n\t)", result); + } +} From 21b8a41f4f3da5c0c9c9f628f0af06152bb3b508 Mon Sep 17 00:00:00 2001 From: wenshao Date: Sat, 2 Feb 2013 13:48:48 +0800 Subject: [PATCH 08/15] add PagerUtils --- .../com/alibaba/druid/sql/PagerUtils.java | 106 +++++++++++++++--- src/test/java/PagerUtils/PagerUtilsTest0.java | 12 +- .../PagerUtils/PagerUtilsTestLimit_0.java | 44 ++++++++ 3 files changed, 145 insertions(+), 17 deletions(-) create mode 100644 src/test/java/PagerUtils/PagerUtilsTestLimit_0.java diff --git a/src/main/java/com/alibaba/druid/sql/PagerUtils.java b/src/main/java/com/alibaba/druid/sql/PagerUtils.java index f576a30b37..4f75c76399 100644 --- a/src/main/java/com/alibaba/druid/sql/PagerUtils.java +++ b/src/main/java/com/alibaba/druid/sql/PagerUtils.java @@ -1,3 +1,18 @@ +/* + * 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.sql; import java.util.List; @@ -5,6 +20,7 @@ import java.util.List; import com.alibaba.druid.sql.ast.SQLStatement; import com.alibaba.druid.sql.ast.expr.SQLAggregateExpr; import com.alibaba.druid.sql.ast.expr.SQLAllColumnExpr; +import com.alibaba.druid.sql.ast.expr.SQLNumberExpr; import com.alibaba.druid.sql.ast.statement.SQLSelect; import com.alibaba.druid.sql.ast.statement.SQLSelectItem; import com.alibaba.druid.sql.ast.statement.SQLSelectQuery; @@ -13,6 +29,7 @@ import com.alibaba.druid.sql.ast.statement.SQLSelectStatement; import com.alibaba.druid.sql.ast.statement.SQLSubqueryTableSource; import com.alibaba.druid.sql.ast.statement.SQLUnionQuery; 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.oracle.ast.expr.OracleAggregateExpr; import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleSelectQueryBlock; import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGSelectQueryBlock; @@ -35,15 +52,63 @@ public class PagerUtils { } SQLSelectStatement selectStmt = (SQLSelectStatement) stmt; - - return count(selectStmt, dbType); + return count(selectStmt.getSelect(), dbType); } + + public static String limit(String sql, String dbType, int offset, int count) { + List stmtList = SQLUtils.parseStatements(sql, dbType); - private static String count(SQLSelectStatement stmt, String dbType) { - SQLSelect select = stmt.getSelect(); + if (stmtList.size() != 1) { + throw new IllegalArgumentException("sql not support count : " + sql); + } + + SQLStatement stmt = stmtList.get(0); + + if (!(stmt instanceof SQLSelectStatement)) { + throw new IllegalArgumentException("sql not support count : " + sql); + } + + SQLSelectStatement selectStmt = (SQLSelectStatement) stmt; + + return limit(selectStmt.getSelect(), dbType, offset, count); + } + + public static String limit(SQLSelect select, String dbType, int offset, int count) { + SQLSelectQuery query = select.getQuery(); + + if (query instanceof SQLSelectQueryBlock) { + return limit((SQLSelectQueryBlock) query, dbType, offset, count); + } + throw new UnsupportedOperationException(); + } + + public static String limit(SQLSelectQueryBlock queryBlock, String dbType, int offset, int count) { + if (JdbcConstants.MYSQL.equals(dbType)) { + return limitMySql((MySqlSelectQueryBlock) queryBlock, dbType, offset, count); + } + throw new UnsupportedOperationException(); + } + + public static String limitMySql(MySqlSelectQueryBlock queryBlock, String dbType, int offset, int count) { + if (queryBlock.getLimit() != null) { + throw new IllegalArgumentException("limit already exists."); + } + + Limit limit = new Limit(); + if (offset > 0) { + limit.setOffset(new SQLNumberExpr(offset)); + } + limit.setRowCount(new SQLNumberExpr(count)); + queryBlock.setLimit(limit); + + return SQLUtils.toSQLString(queryBlock, dbType); + } + + private static String count(SQLSelect select, String dbType) { if (select.getOrderBy() != null) { select.setOrderBy(null); } + SQLSelectQuery query = select.getQuery(); clearOrderBy(query); @@ -51,26 +116,35 @@ public class PagerUtils { SQLSelectItem countItem = createCountItem(dbType); SQLSelectQueryBlock queryBlock = (SQLSelectQueryBlock) query; + + if (queryBlock.getGroupBy() != null && queryBlock.getGroupBy().getItems().size() > 0) { + return createCountUseSubQuery(select, dbType); + } + queryBlock.getSelectList().clear(); queryBlock.getSelectList().add(countItem); - return SQLUtils.toSQLString(stmt, dbType); + return SQLUtils.toSQLString(select, dbType); } else if (query instanceof SQLUnionQuery) { - SQLSelectQueryBlock countSelectQuery = createQueryBlock(dbType); - - SQLSelectItem countItem = createCountItem(dbType); - countSelectQuery.getSelectList().add(countItem); - - countSelectQuery.setFrom(new SQLSubqueryTableSource(select)); - - SQLSelect countSelect = new SQLSelect(countSelectQuery); - SQLSelectStatement countStmt = new SQLSelectStatement(countSelect); - - return SQLUtils.toSQLString(countStmt, dbType); + return createCountUseSubQuery(select, dbType); } throw new IllegalStateException(); } + private static String createCountUseSubQuery(SQLSelect select, String dbType) { + SQLSelectQueryBlock countSelectQuery = createQueryBlock(dbType); + + SQLSelectItem countItem = createCountItem(dbType); + countSelectQuery.getSelectList().add(countItem); + + countSelectQuery.setFrom(new SQLSubqueryTableSource(select)); + + SQLSelect countSelect = new SQLSelect(countSelectQuery); + SQLSelectStatement countStmt = new SQLSelectStatement(countSelect); + + return SQLUtils.toSQLString(countStmt, dbType); + } + private static SQLSelectQueryBlock createQueryBlock(String dbType) { if (JdbcConstants.MYSQL.equals(dbType)) { return new MySqlSelectQueryBlock(); diff --git a/src/test/java/PagerUtils/PagerUtilsTest0.java b/src/test/java/PagerUtils/PagerUtilsTest0.java index 0cff3af24a..b9508d8e79 100644 --- a/src/test/java/PagerUtils/PagerUtilsTest0.java +++ b/src/test/java/PagerUtils/PagerUtilsTest0.java @@ -30,7 +30,17 @@ public class PagerUtilsTest0 extends TestCase { "FROM t", result); } - public void test_mysql_3() throws Exception { + public void test_mysql_group_0() throws Exception { + String sql = "select type, count(*) from t group by type"; + String result = PagerUtils.count(sql, JdbcConstants.MYSQL); + Assert.assertEquals("SELECT COUNT(*)" + // + "\nFROM (SELECT type, COUNT(*)" + // + "\n\tFROM t" + // + "\n\tGROUP BY type" + // + "\n\t)", result); + } + + public void test_mysql_union_0() throws Exception { String sql = "select id, name from t1 union select id, name from t2 order by id"; String result = PagerUtils.count(sql, JdbcConstants.MYSQL); Assert.assertEquals("SELECT COUNT(*)\n" + // diff --git a/src/test/java/PagerUtils/PagerUtilsTestLimit_0.java b/src/test/java/PagerUtils/PagerUtilsTestLimit_0.java new file mode 100644 index 0000000000..86058a7766 --- /dev/null +++ b/src/test/java/PagerUtils/PagerUtilsTestLimit_0.java @@ -0,0 +1,44 @@ +package PagerUtils; + +import junit.framework.TestCase; + +import org.junit.Assert; + +import com.alibaba.druid.sql.PagerUtils; +import com.alibaba.druid.util.JdbcConstants; + +public class PagerUtilsTestLimit_0 extends TestCase { + + public void test_mysql_0() throws Exception { + String sql = "select * from t"; + String result = PagerUtils.limit(sql, JdbcConstants.MYSQL, 0, 10); + Assert.assertEquals("SELECT *" + // + "\nFROM t" + // + "\nLIMIT 10", result); + } + + public void test_mysql_1() throws Exception { + String sql = "select * from t"; + String result = PagerUtils.limit(sql, JdbcConstants.MYSQL, 10, 10); + Assert.assertEquals("SELECT *" + // + "\nFROM t" + // + "\nLIMIT 10, 10", result); + } + + public void test_mysql_2() throws Exception { + String sql = "select * from t"; + String result = PagerUtils.limit(sql, JdbcConstants.MYSQL, 20, 10); + Assert.assertEquals("SELECT *" + // + "\nFROM t" + // + "\nLIMIT 20, 10", result); + } + + public void test_mysql_3() throws Exception { + String sql = "select id, name, salary from t order by id, name"; + String result = PagerUtils.limit(sql, JdbcConstants.MYSQL, 20, 10); + Assert.assertEquals("SELECT id, name, salary" + // + "\nFROM t" + // + "\nORDER BY id, name" + // + "\nLIMIT 20, 10", result); + } +} From 1fa03bb01eb68a319f60a7151b42be1f98898dca Mon Sep 17 00:00:00 2001 From: wenshao Date: Sat, 2 Feb 2013 13:51:39 +0800 Subject: [PATCH 09/15] add PagerUtils --- .../alibaba/druid/bvt/sql}/PagerUtilsTest0.java | 2 +- .../alibaba/druid/bvt/sql}/PagerUtilsTestLimit_0.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/test/java/{PagerUtils => com/alibaba/druid/bvt/sql}/PagerUtilsTest0.java (98%) rename src/test/java/{PagerUtils => com/alibaba/druid/bvt/sql}/PagerUtilsTestLimit_0.java (97%) diff --git a/src/test/java/PagerUtils/PagerUtilsTest0.java b/src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTest0.java similarity index 98% rename from src/test/java/PagerUtils/PagerUtilsTest0.java rename to src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTest0.java index b9508d8e79..d6271da251 100644 --- a/src/test/java/PagerUtils/PagerUtilsTest0.java +++ b/src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTest0.java @@ -1,4 +1,4 @@ -package PagerUtils; +package com.alibaba.druid.bvt.sql; import junit.framework.TestCase; diff --git a/src/test/java/PagerUtils/PagerUtilsTestLimit_0.java b/src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTestLimit_0.java similarity index 97% rename from src/test/java/PagerUtils/PagerUtilsTestLimit_0.java rename to src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTestLimit_0.java index 86058a7766..38382bc614 100644 --- a/src/test/java/PagerUtils/PagerUtilsTestLimit_0.java +++ b/src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTestLimit_0.java @@ -1,4 +1,4 @@ -package PagerUtils; +package com.alibaba.druid.bvt.sql; import junit.framework.TestCase; From cd6140c5bf7f44e706745a8dfb0a57a6bfcbbb4f Mon Sep 17 00:00:00 2001 From: wenshao Date: Sat, 2 Feb 2013 15:53:23 +0800 Subject: [PATCH 10/15] add PagerUtils oracle support --- .../com/alibaba/druid/sql/PagerUtils.java | 107 +++++++++++++----- .../postgresql/visitor/PGOutputVisitor.java | 2 +- ...java => PagerUtilsTest_Count_MySql_0.java} | 2 +- ...java => PagerUtilsTest_Limit_mysql_0.java} | 2 +- 4 files changed, 84 insertions(+), 29 deletions(-) rename src/test/java/com/alibaba/druid/bvt/sql/{PagerUtilsTest0.java => PagerUtilsTest_Count_MySql_0.java} (97%) rename src/test/java/com/alibaba/druid/bvt/sql/{PagerUtilsTestLimit_0.java => PagerUtilsTest_Limit_mysql_0.java} (96%) diff --git a/src/main/java/com/alibaba/druid/sql/PagerUtils.java b/src/main/java/com/alibaba/druid/sql/PagerUtils.java index 4f75c76399..764543b3d4 100644 --- a/src/main/java/com/alibaba/druid/sql/PagerUtils.java +++ b/src/main/java/com/alibaba/druid/sql/PagerUtils.java @@ -17,10 +17,15 @@ package com.alibaba.druid.sql; import java.util.List; +import com.alibaba.druid.sql.ast.SQLExpr; import com.alibaba.druid.sql.ast.SQLStatement; import com.alibaba.druid.sql.ast.expr.SQLAggregateExpr; import com.alibaba.druid.sql.ast.expr.SQLAllColumnExpr; +import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr; +import com.alibaba.druid.sql.ast.expr.SQLBinaryOperator; +import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr; import com.alibaba.druid.sql.ast.expr.SQLNumberExpr; +import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr; import com.alibaba.druid.sql.ast.statement.SQLSelect; import com.alibaba.druid.sql.ast.statement.SQLSelectItem; import com.alibaba.druid.sql.ast.statement.SQLSelectQuery; @@ -54,7 +59,7 @@ public class PagerUtils { SQLSelectStatement selectStmt = (SQLSelectStatement) stmt; return count(selectStmt.getSelect(), dbType); } - + public static String limit(String sql, String dbType, int offset, int count) { List stmtList = SQLUtils.parseStatements(sql, dbType); @@ -69,58 +74,108 @@ public class PagerUtils { } SQLSelectStatement selectStmt = (SQLSelectStatement) stmt; - + return limit(selectStmt.getSelect(), dbType, offset, count); } - + public static String limit(SQLSelect select, String dbType, int offset, int count) { SQLSelectQuery query = select.getQuery(); - + + if (JdbcConstants.ORACLE.equals(dbType)) { + return limitOracle(select, dbType, offset, count); + } + if (query instanceof SQLSelectQueryBlock) { - return limit((SQLSelectQueryBlock) query, dbType, offset, count); + return limitQueryBlock(select, dbType, offset, count); } + throw new UnsupportedOperationException(); } - - public static String limit(SQLSelectQueryBlock queryBlock, String dbType, int offset, int count) { + + private static String limitQueryBlock(SQLSelect select, String dbType, int offset, int count) { + SQLSelectQueryBlock queryBlock = (SQLSelectQueryBlock) select.getQuery(); if (JdbcConstants.MYSQL.equals(dbType)) { - return limitMySql((MySqlSelectQueryBlock) queryBlock, dbType, offset, count); + return limitMySqlQueryBlock((MySqlSelectQueryBlock) queryBlock, dbType, offset, count); } + throw new UnsupportedOperationException(); } - - public static String limitMySql(MySqlSelectQueryBlock queryBlock, String dbType, int offset, int count) { + + private static String limitOracle(SQLSelect select, String dbType, int offset, int count) { + SQLSelectQuery query = select.getQuery(); + + if (query instanceof SQLSelectQueryBlock) { + OracleSelectQueryBlock queryBlock = (OracleSelectQueryBlock) query; + if (select.getOrderBy() == null && offset <= 0) { + SQLExpr condition = new SQLBinaryOpExpr(new SQLIdentifierExpr("ROWNUM"), // + SQLBinaryOperator.LessThanOrEqual, // + new SQLNumberExpr(count)); + if (queryBlock.getWhere() == null) { + queryBlock.setWhere(condition); + } else { + queryBlock.setWhere(new SQLBinaryOpExpr(queryBlock.getWhere(), // + SQLBinaryOperator.BooleanAnd, // + condition)); + } + + return SQLUtils.toSQLString(select, dbType); + } + } + + OracleSelectQueryBlock countQueryBlock = new OracleSelectQueryBlock(); + countQueryBlock.getSelectList().add(new SQLSelectItem(new SQLPropertyExpr(new SQLIdentifierExpr("_X"), "*"))); + countQueryBlock.getSelectList().add(new SQLSelectItem(new SQLIdentifierExpr("ROWNUM"), "_RN")); + + countQueryBlock.setFrom(new SQLSubqueryTableSource(select, "_X")); + countQueryBlock.setWhere(new SQLBinaryOpExpr(new SQLIdentifierExpr("ROWNUM"), // + SQLBinaryOperator.LessThanOrEqual, // + new SQLNumberExpr(count + offset))); + if (offset <= 0) { + return SQLUtils.toSQLString(countQueryBlock, dbType); + } + + OracleSelectQueryBlock offsetQueryBlock = new OracleSelectQueryBlock(); + offsetQueryBlock.getSelectList().add(new SQLSelectItem(new SQLAllColumnExpr())); + offsetQueryBlock.setFrom(new SQLSubqueryTableSource(new SQLSelect(countQueryBlock), "_XX")); + offsetQueryBlock.setWhere(new SQLBinaryOpExpr(new SQLIdentifierExpr("_RN"), // + SQLBinaryOperator.GreaterThan, // + new SQLNumberExpr(offset))); + + return SQLUtils.toSQLString(offsetQueryBlock, dbType); + } + + private static String limitMySqlQueryBlock(MySqlSelectQueryBlock queryBlock, String dbType, int offset, int count) { if (queryBlock.getLimit() != null) { throw new IllegalArgumentException("limit already exists."); } - + Limit limit = new Limit(); if (offset > 0) { limit.setOffset(new SQLNumberExpr(offset)); } limit.setRowCount(new SQLNumberExpr(count)); queryBlock.setLimit(limit); - + return SQLUtils.toSQLString(queryBlock, dbType); } - + private static String count(SQLSelect select, String dbType) { if (select.getOrderBy() != null) { select.setOrderBy(null); } - + SQLSelectQuery query = select.getQuery(); clearOrderBy(query); if (query instanceof SQLSelectQueryBlock) { SQLSelectItem countItem = createCountItem(dbType); - + SQLSelectQueryBlock queryBlock = (SQLSelectQueryBlock) query; - + if (queryBlock.getGroupBy() != null && queryBlock.getGroupBy().getItems().size() > 0) { - return createCountUseSubQuery(select, dbType); + return createCountUseSubQuery(select, dbType); } - + queryBlock.getSelectList().clear(); queryBlock.getSelectList().add(countItem); return SQLUtils.toSQLString(select, dbType); @@ -133,15 +188,15 @@ public class PagerUtils { private static String createCountUseSubQuery(SQLSelect select, String dbType) { SQLSelectQueryBlock countSelectQuery = createQueryBlock(dbType); - + SQLSelectItem countItem = createCountItem(dbType); countSelectQuery.getSelectList().add(countItem); - + countSelectQuery.setFrom(new SQLSubqueryTableSource(select)); - + SQLSelect countSelect = new SQLSelect(countSelectQuery); SQLSelectStatement countStmt = new SQLSelectStatement(countSelect); - + return SQLUtils.toSQLString(countStmt, dbType); } @@ -149,19 +204,19 @@ public class PagerUtils { if (JdbcConstants.MYSQL.equals(dbType)) { return new MySqlSelectQueryBlock(); } - + if (JdbcConstants.ORACLE.equals(dbType)) { return new OracleSelectQueryBlock(); } - + if (JdbcConstants.POSTGRESQL.equals(dbType)) { return new PGSelectQueryBlock(); } - + if (JdbcConstants.SQL_SERVER.equals(dbType)) { return new SQLServerSelectQueryBlock(); } - + return new SQLSelectQueryBlock(); } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGOutputVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGOutputVisitor.java index b9bea852e3..254d97833d 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGOutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/visitor/PGOutputVisitor.java @@ -197,7 +197,7 @@ public class PGOutputVisitor extends SQLASTOutputVisitor implements PGASTVisitor } if (x.getGroupBy() != null) { - print(" "); + println(); x.getGroupBy().accept(this); } diff --git a/src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTest0.java b/src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTest_Count_MySql_0.java similarity index 97% rename from src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTest0.java rename to src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTest_Count_MySql_0.java index d6271da251..4ca0b17534 100644 --- a/src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTest0.java +++ b/src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTest_Count_MySql_0.java @@ -7,7 +7,7 @@ import org.junit.Assert; import com.alibaba.druid.sql.PagerUtils; import com.alibaba.druid.util.JdbcConstants; -public class PagerUtilsTest0 extends TestCase { +public class PagerUtilsTest_Count_MySql_0 extends TestCase { public void test_mysql_0() throws Exception { String sql = "select * from t"; diff --git a/src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTestLimit_0.java b/src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTest_Limit_mysql_0.java similarity index 96% rename from src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTestLimit_0.java rename to src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTest_Limit_mysql_0.java index 38382bc614..1363ae19f6 100644 --- a/src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTestLimit_0.java +++ b/src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTest_Limit_mysql_0.java @@ -7,7 +7,7 @@ import org.junit.Assert; import com.alibaba.druid.sql.PagerUtils; import com.alibaba.druid.util.JdbcConstants; -public class PagerUtilsTestLimit_0 extends TestCase { +public class PagerUtilsTest_Limit_mysql_0 extends TestCase { public void test_mysql_0() throws Exception { String sql = "select * from t"; From 84f30ff2edf6aed744a7a0c7aa3bccde1d0a079f Mon Sep 17 00:00:00 2001 From: wenshao Date: Sat, 2 Feb 2013 15:53:36 +0800 Subject: [PATCH 11/15] add PagerUtils oracle support --- .../sql/PagerUtilsTest_Count_Oracle_0.java | 54 ++++++++++++++ .../bvt/sql/PagerUtilsTest_Count_PG_0.java | 54 ++++++++++++++ .../sql/PagerUtilsTest_Count_SQLServer_0.java | 54 ++++++++++++++ .../sql/PagerUtilsTest_Limit_oracle_0.java | 70 +++++++++++++++++++ 4 files changed, 232 insertions(+) create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTest_Count_Oracle_0.java create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTest_Count_PG_0.java create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTest_Count_SQLServer_0.java create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTest_Limit_oracle_0.java diff --git a/src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTest_Count_Oracle_0.java b/src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTest_Count_Oracle_0.java new file mode 100644 index 0000000000..8d5384b978 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTest_Count_Oracle_0.java @@ -0,0 +1,54 @@ +package com.alibaba.druid.bvt.sql; + +import junit.framework.TestCase; + +import org.junit.Assert; + +import com.alibaba.druid.sql.PagerUtils; +import com.alibaba.druid.util.JdbcConstants; + +public class PagerUtilsTest_Count_Oracle_0 extends TestCase { + + public void test_oracle_0() throws Exception { + String sql = "select * from t"; + String result = PagerUtils.count(sql, JdbcConstants.ORACLE); + Assert.assertEquals("SELECT COUNT(*)\n" + // + "FROM t", result); + } + + public void test_oracle_1() throws Exception { + String sql = "select id, name from t"; + String result = PagerUtils.count(sql, JdbcConstants.ORACLE); + Assert.assertEquals("SELECT COUNT(*)\n" + // + "FROM t", result); + } + + public void test_oracle_2() throws Exception { + String sql = "select id, name from t order by id"; + String result = PagerUtils.count(sql, JdbcConstants.ORACLE); + Assert.assertEquals("SELECT COUNT(*)\n" + // + "FROM t", result); + } + + public void test_oracle_group_0() throws Exception { + String sql = "select type, count(*) from t group by type"; + String result = PagerUtils.count(sql, JdbcConstants.ORACLE); + Assert.assertEquals("SELECT COUNT(*)" + // + "\nFROM (SELECT type, COUNT(*)" + // + "\n\tFROM t" + // + "\n\tGROUP BY type" + // + "\n\t)", result); + } + + public void test_oracle_union_0() throws Exception { + String sql = "select id, name from t1 union select id, name from t2 order by id"; + String result = PagerUtils.count(sql, JdbcConstants.ORACLE); + Assert.assertEquals("SELECT COUNT(*)\n" + // + "FROM (SELECT id, name" + // + "\n\tFROM t1" + // + "\n\tUNION" + // + "\n\tSELECT id, name" + // + "\n\tFROM t2" + // + "\n\t)", result); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTest_Count_PG_0.java b/src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTest_Count_PG_0.java new file mode 100644 index 0000000000..fdc02bba67 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTest_Count_PG_0.java @@ -0,0 +1,54 @@ +package com.alibaba.druid.bvt.sql; + +import junit.framework.TestCase; + +import org.junit.Assert; + +import com.alibaba.druid.sql.PagerUtils; +import com.alibaba.druid.util.JdbcConstants; + +public class PagerUtilsTest_Count_PG_0 extends TestCase { + + public void test_pg_0() throws Exception { + String sql = "select * from t"; + String result = PagerUtils.count(sql, JdbcConstants.POSTGRESQL); + Assert.assertEquals("SELECT COUNT(*)\n" + // + "FROM t", result); + } + + public void test_pg_1() throws Exception { + String sql = "select id, name from t"; + String result = PagerUtils.count(sql, JdbcConstants.POSTGRESQL); + Assert.assertEquals("SELECT COUNT(*)\n" + // + "FROM t", result); + } + + public void test_pg_2() throws Exception { + String sql = "select id, name from t order by id"; + String result = PagerUtils.count(sql, JdbcConstants.POSTGRESQL); + Assert.assertEquals("SELECT COUNT(*)\n" + // + "FROM t", result); + } + + public void test_pg_group_0() throws Exception { + String sql = "select type, count(*) from t group by type"; + String result = PagerUtils.count(sql, JdbcConstants.POSTGRESQL); + Assert.assertEquals("SELECT COUNT(*)" + // + "\nFROM (SELECT type, COUNT(*)" + // + "\n\tFROM t" + // + "\n\tGROUP BY type" + // + "\n\t)", result); + } + + public void test_pg_union_0() throws Exception { + String sql = "select id, name from t1 union select id, name from t2 order by id"; + String result = PagerUtils.count(sql, JdbcConstants.POSTGRESQL); + Assert.assertEquals("SELECT COUNT(*)\n" + // + "FROM (SELECT id, name" + // + "\n\tFROM t1" + // + "\n\tUNION" + // + "\n\tSELECT id, name" + // + "\n\tFROM t2" + // + "\n\t)", result); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTest_Count_SQLServer_0.java b/src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTest_Count_SQLServer_0.java new file mode 100644 index 0000000000..2d64e340b2 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTest_Count_SQLServer_0.java @@ -0,0 +1,54 @@ +package com.alibaba.druid.bvt.sql; + +import junit.framework.TestCase; + +import org.junit.Assert; + +import com.alibaba.druid.sql.PagerUtils; +import com.alibaba.druid.util.JdbcConstants; + +public class PagerUtilsTest_Count_SQLServer_0 extends TestCase { + + public void test_sqlserver_0() throws Exception { + String sql = "select * from t"; + String result = PagerUtils.count(sql, JdbcConstants.SQL_SERVER); + Assert.assertEquals("SELECT COUNT(*)\n" + // + "FROM t", result); + } + + public void test_sqlserver_1() throws Exception { + String sql = "select id, name from t"; + String result = PagerUtils.count(sql, JdbcConstants.SQL_SERVER); + Assert.assertEquals("SELECT COUNT(*)\n" + // + "FROM t", result); + } + + public void test_sqlserver_2() throws Exception { + String sql = "select id, name from t order by id"; + String result = PagerUtils.count(sql, JdbcConstants.SQL_SERVER); + Assert.assertEquals("SELECT COUNT(*)\n" + // + "FROM t", result); + } + + public void test_sqlserver_group_0() throws Exception { + String sql = "select type, count(*) from t group by type"; + String result = PagerUtils.count(sql, JdbcConstants.SQL_SERVER); + Assert.assertEquals("SELECT COUNT(*)" + // + "\nFROM (SELECT type, COUNT(*)" + // + "\n\tFROM t" + // + "\n\tGROUP BY type" + // + "\n\t)", result); + } + + public void test_sqlserver_union_0() throws Exception { + String sql = "select id, name from t1 union select id, name from t2 order by id"; + String result = PagerUtils.count(sql, JdbcConstants.SQL_SERVER); + Assert.assertEquals("SELECT COUNT(*)\n" + // + "FROM (SELECT id, name" + // + "\n\tFROM t1" + // + "\n\tUNION" + // + "\n\tSELECT id, name" + // + "\n\tFROM t2" + // + "\n\t)", result); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTest_Limit_oracle_0.java b/src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTest_Limit_oracle_0.java new file mode 100644 index 0000000000..6481dca199 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/PagerUtilsTest_Limit_oracle_0.java @@ -0,0 +1,70 @@ +package com.alibaba.druid.bvt.sql; + +import junit.framework.TestCase; + +import org.junit.Assert; + +import com.alibaba.druid.sql.PagerUtils; +import com.alibaba.druid.util.JdbcConstants; + +public class PagerUtilsTest_Limit_oracle_0 extends TestCase { + + public void test_oracle_oderby_0() throws Exception { + String sql = "select * from t order by id"; + String result = PagerUtils.limit(sql, JdbcConstants.ORACLE, 0, 10); + Assert.assertEquals("SELECT _X.*, ROWNUM AS _RN" + // + "\nFROM (SELECT *" + // + "\n\tFROM t" + // + "\n\tORDER BY id" + // + "\n\t) _X" + // + "\nWHERE ROWNUM <= 10", result); + } + + public void test_oracle_0() throws Exception { + String sql = "select * from t"; + String result = PagerUtils.limit(sql, JdbcConstants.ORACLE, 0, 10); + Assert.assertEquals("SELECT *" + // + "\nFROM t" + // + "\nWHERE ROWNUM <= 10", result); + } + + public void test_oracle_1() throws Exception { + String sql = "select * from t"; + String result = PagerUtils.limit(sql, JdbcConstants.ORACLE, 10, 10); + Assert.assertEquals("SELECT *" + // + "\nFROM (SELECT _X.*, ROWNUM AS _RN" + // + "\n\tFROM (SELECT *" + // + "\n\t\tFROM t" + // + "\n\t\t) _X" + // + "\n\tWHERE ROWNUM <= 20" + // + "\n\t) _XX" + // + "\nWHERE _RN > 10", result); + } + + public void test_oracle_2() throws Exception { + String sql = "select * from t"; + String result = PagerUtils.limit(sql, JdbcConstants.ORACLE, 20, 10); + Assert.assertEquals("SELECT *" + // + "\nFROM (SELECT _X.*, ROWNUM AS _RN" + // + "\n\tFROM (SELECT *" + // + "\n\t\tFROM t" + // + "\n\t\t) _X" + // + "\n\tWHERE ROWNUM <= 30" + // + "\n\t) _XX" + // + "\nWHERE _RN > 20", result); + } + + public void test_oracle_3() throws Exception { + String sql = "select id, name, salary from t order by id, name"; + String result = PagerUtils.limit(sql, JdbcConstants.ORACLE, 20, 10); + Assert.assertEquals("SELECT *" + // + "\nFROM (SELECT _X.*, ROWNUM AS _RN" + // + "\n\tFROM (SELECT id, name, salary" + // + "\n\t\tFROM t" + // + "\n\t\tORDER BY id, name" + // + "\n\t\t) _X" + // + "\n\tWHERE ROWNUM <= 30" + // + "\n\t) _XX" + // + "\nWHERE _RN > 20", result); + } +} From c0c28920240d9f803514d3c00d296a0116bf20cd Mon Sep 17 00:00:00 2001 From: wenshao Date: Sat, 2 Feb 2013 20:33:57 +0800 Subject: [PATCH 12/15] bug fixed for sql parser --- .../alibaba/druid/sql/visitor/SQLASTOutputVisitor.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java index 09cd66d802..f1fc43ce06 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java @@ -1292,12 +1292,14 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter { @Override public boolean visit(SQLOver x) { print("OVER ("); - printAndAccept(x.getPartitionBy(), ", "); - print(")"); + if (x.getPartitionBy().size() > 0) { + printAndAccept(x.getPartitionBy(), ", "); + print(' '); + } if (x.getOrderBy() != null) { - print(" "); x.getOrderBy().accept(this); } + print(")"); return false; } From 86cc81ff4f0a8a12d8734086970c53f4375199c9 Mon Sep 17 00:00:00 2001 From: wenshao Date: Sun, 3 Feb 2013 15:24:39 +0800 Subject: [PATCH 13/15] add testcase --- .../sql/sqlserver/SQLServerSelectTest12.java | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 src/test/java/com/alibaba/druid/bvt/sql/sqlserver/SQLServerSelectTest12.java diff --git a/src/test/java/com/alibaba/druid/bvt/sql/sqlserver/SQLServerSelectTest12.java b/src/test/java/com/alibaba/druid/bvt/sql/sqlserver/SQLServerSelectTest12.java new file mode 100644 index 0000000000..854d3677ab --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/sqlserver/SQLServerSelectTest12.java @@ -0,0 +1,52 @@ +/* + * 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.sqlserver; + +import junit.framework.TestCase; + +import org.junit.Assert; + +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.dialect.sqlserver.parser.SQLServerStatementParser; +import com.alibaba.druid.sql.test.TestUtils; + +public class SQLServerSelectTest12 extends TestCase { + + public void test_simple() throws Exception { + String sql = "SELECT Row, Name " + // + "FROM(" + // + "SELECT ROW_NUMBER() OVER (ORDER BY ProductID) AS Row, Name " + // + "FROM Product " + // + ") AS ProductsWithRowNumbers " + // + "WHERE Row >= 6 AND Row <= 10"; + + String expect = "SELECT Row, Name" + // + "\nFROM (SELECT ROW_NUMBER() OVER (ORDER BY ProductID) AS Row, Name" + // + "\n\tFROM Product" + // + "\n\t) ProductsWithRowNumbers" + // + "\nWHERE Row >= 6" + // + "\n\tAND Row <= 10"; + + SQLServerStatementParser parser = new SQLServerStatementParser(sql); + SQLStatement stmt = parser.parseStatementList().get(0); + + String text = TestUtils.outputSqlServer(stmt); + + Assert.assertEquals(expect, text); + + System.out.println(text); + } +} From cd5052f1794a3e88e35d725b1c2a58344590ec1c Mon Sep 17 00:00:00 2001 From: wenshao Date: Sun, 3 Feb 2013 18:35:26 +0800 Subject: [PATCH 14/15] sql parser refactor, rename field --- .../oracle/parser/OracleExprParser.java | 60 +++++++++++++++---- 1 file changed, 49 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleExprParser.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleExprParser.java index 08d42327dd..fea691cea9 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleExprParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleExprParser.java @@ -80,20 +80,58 @@ public class OracleExprParser extends SQLExprParser { + + + + + + + + public boolean allowStringAdditive = false; /** * @formatter:off */ - private static final String[] _aggregateFunctions = { // - "AVG", "CORR", "COVAR_POP", "COVAR_SAMP", "COUNT", // - "CUME_DIST", "DENSE_RANK", "FIRST", "FIRST_VALUE", // - "LAG", "LAST", "LAST_VALUE", "LEAD", "MAX", "MIN", // - "NTILE", "PERCENT_RANK", "PERCENTILE_CONT", "PERCENTILE_DISC", "RANK", // - "RATIO_TO_REPORT", "REGR_SLOPE", "REGR_INTERCEPT", "REGR_COUNT", "REGR_R2", // - "REGR_AVGX", "REGR_AVGY", "REGR_SXX", "REGR_SYY", "REGR_SXY", // - "ROW_NUMBER", "STDDEV", "STDDEV_POP", "STDDEV_SAMP", "SUM", // - "VAR_POP", "VAR_SAMP", "VARIANCE" // + private static final String[] AGGREGATE_FUNCTIONS = { + "AVG", // + "CORR", // + "COVAR_POP", // + "COVAR_SAMP", // + "COUNT", // + "CUME_DIST", // + "DENSE_RANK", // + "FIRST", // + "FIRST_VALUE", // + "LAG", // + "LAST", // + "LAST_VALUE", // + "LEAD", // + "MAX", // + "MIN", // + "NTILE", // + "PERCENT_RANK", // + "PERCENTILE_CONT", // + "PERCENTILE_DISC", // + "RANK", // + "RATIO_TO_REPORT", // + "REGR_SLOPE", // + "REGR_INTERCEPT", // + "REGR_COUNT", // + "REGR_R2", // + "REGR_AVGX", // + "REGR_AVGY", // + "REGR_SXX", // + "REGR_SYY", // + "REGR_SXY", // + "ROW_NUMBER", // + "STDDEV", // + "STDDEV_POP", // + "STDDEV_SAMP", // + "SUM", // + "VAR_POP", // + "VAR_SAMP", // + "VARIANCE" // }; public OracleExprParser(Lexer lexer){ @@ -229,8 +267,8 @@ public class OracleExprParser extends SQLExprParser { } public boolean isAggreateFunction(String word) { - for (int i = 0; i < _aggregateFunctions.length; ++i) { - if (_aggregateFunctions[i].compareToIgnoreCase(word) == 0) { + for (int i = 0; i < AGGREGATE_FUNCTIONS.length; ++i) { + if (AGGREGATE_FUNCTIONS[i].compareToIgnoreCase(word) == 0) { return true; } } From 6dd5510b3b3f1478436e7b886e272960540d05f4 Mon Sep 17 00:00:00 2001 From: wenshao Date: Tue, 5 Feb 2013 18:42:36 +0800 Subject: [PATCH 15/15] bug fixed for multi-tenant --- .../druid/wall/spi/WallVisitorUtils.java | 7 ++- .../bvt/filter/wall/TenantSelectTest4.java | 57 +++++++++++++++++++ 2 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 src/test/java/com/alibaba/druid/bvt/filter/wall/TenantSelectTest4.java diff --git a/src/main/java/com/alibaba/druid/wall/spi/WallVisitorUtils.java b/src/main/java/com/alibaba/druid/wall/spi/WallVisitorUtils.java index 830baf67a6..bb29297f65 100644 --- a/src/main/java/com/alibaba/druid/wall/spi/WallVisitorUtils.java +++ b/src/main/java/com/alibaba/druid/wall/spi/WallVisitorUtils.java @@ -132,18 +132,21 @@ public class WallVisitorUtils { checkCondition(visitor, x.getWhere()); if (Boolean.TRUE == getValue(where)) { + boolean isSimpleConstExpr = false; if (where instanceof SQLBinaryOpExpr) { SQLBinaryOpExpr binaryOpExpr = (SQLBinaryOpExpr) where; if (binaryOpExpr.getOperator() == SQLBinaryOperator.Equality || binaryOpExpr.getOperator() == SQLBinaryOperator.NotEqual) { if (binaryOpExpr.getLeft() instanceof SQLIntegerExpr && binaryOpExpr.getRight() instanceof SQLIntegerExpr) { - return; + isSimpleConstExpr = true; } } } - addViolation(visitor, x); + if (!isSimpleConstExpr) { + addViolation(visitor, x); + } } } diff --git a/src/test/java/com/alibaba/druid/bvt/filter/wall/TenantSelectTest4.java b/src/test/java/com/alibaba/druid/bvt/filter/wall/TenantSelectTest4.java new file mode 100644 index 0000000000..df461be3d8 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/filter/wall/TenantSelectTest4.java @@ -0,0 +1,57 @@ +/* + * 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.filter.wall; + +import junit.framework.TestCase; + +import org.junit.Assert; + +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.util.JdbcConstants; +import com.alibaba.druid.wall.WallCheckResult; +import com.alibaba.druid.wall.WallConfig; +import com.alibaba.druid.wall.WallProvider; +import com.alibaba.druid.wall.spi.MySqlWallProvider; + +public class TenantSelectTest4 extends TestCase { + + private String sql = "SELECT a.*,b.name " + // + "FROM vote_info a left join vote_item b on a.item_id=b.id " + // + "where 1=1 limit 1,10"; + + private WallConfig config = new WallConfig(); + + protected void setUp() throws Exception { + config.setTenantTablePattern("*"); + config.setTenantColumn("tenant"); + } + + public void testMySql() throws Exception { + WallProvider.setTenantValue(123); + MySqlWallProvider provider = new MySqlWallProvider(config); + WallCheckResult checkResult = provider.check(sql); + Assert.assertEquals(0, checkResult.getViolations().size()); + + String resultSql = SQLUtils.toSQLString(checkResult.getStatementList(), JdbcConstants.MYSQL); + Assert.assertEquals("SELECT a.*, b.name" + // + "\nFROM vote_info a" + // + "\n\tLEFT JOIN vote_item b ON b.tenant = 123" + // + "\n\t\tAND a.item_id = b.id" + // + "\nWHERE a.tenant = 123" + // + "\n\tAND 1 = 1" + // + "\nLIMIT 1, 10", resultSql); + } +}