diff --git a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLBinaryOperator.java b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLBinaryOperator.java index 096bab6c7c..95d448233c 100644 --- a/src/main/java/com/alibaba/druid/sql/ast/expr/SQLBinaryOperator.java +++ b/src/main/java/com/alibaba/druid/sql/ast/expr/SQLBinaryOperator.java @@ -15,51 +15,66 @@ */ package com.alibaba.druid.sql.ast.expr; +/** + * + * 二元操作符 + * @author wenshao 2011-5-20 下午12:32:02 + * @formatter:off + */ public enum SQLBinaryOperator { - Add("+", 70), Subtract("-", 70), Multiply("*", 60), Divide("/", 60), Concat("||", 140), BitwiseAnd("&", 90), BitwiseNot("!", 130), BitwiseOr("|", 100), - BitwiseXor("^", 50), BooleanAnd("AND", 140), BooleanOr("OR", 160), BooleanXor("XOR", 150), Equality("=", 170), Assignment(":=", 169), - GreaterThan(">", 110), GreaterThanOrEqual(">=", 110), Is("IS", 110), LessThan("<", 110), LessThanOrEqual("<=", 110), LessThanOrEqualOrGreaterThan("<=>", - 110), - LessThanOrGreater("<>", 110), LeftShift("<<", 80), Like("LIKE", 110), RightShift(">>", 80), Modulus("%", 60), NotEqual("!=", 110), NotLessThan("!<", 110), - NotGreaterThan("!>", 110), Union("UNION", 0), NotLike("NOT LIKE", 110), IsNot("IS NOT", 110), Escape("ESCAPE", 110), RegExp("REGEXP", 110), - NotRegExp("NOT REGEXP", 110), COLLATE("COLLATE", 20); + Union("UNION", 0), + COLLATE("COLLATE", 20), + BitwiseXor("^", 50), + + Multiply("*", 60), + Divide("/", 60), + Modulus("%", 60), + + Add("+", 70), + Subtract("-", 70), + + LeftShift("<<", 80), + RightShift(">>", 80), + + BitwiseAnd("&", 90), + BitwiseOr("|", 100), + + GreaterThan(">", 110), + GreaterThanOrEqual(">=", 110), + Is("IS", 110), + LessThan("<", 110), + LessThanOrEqual("<=", 110), + LessThanOrEqualOrGreaterThan("<=>",110), + LessThanOrGreater("<>", 110), + Like("LIKE", 110), + NotEqual("!=", 110), + NotLessThan("!<", 110), + NotGreaterThan("!>", 110), + NotLike("NOT LIKE", 110), + IsNot("IS NOT", 110), + Escape("ESCAPE", 110), + RegExp("REGEXP", 110), + NotRegExp("NOT REGEXP", 110), + Equality("=", 110), + + BitwiseNot("!", 130), + Concat("||", 140), + + BooleanAnd("AND", 140), + BooleanXor("XOR", 150), + BooleanOr("OR", 160), + Assignment(":=", 169), + + ; + + + + public static int getPriority(SQLBinaryOperator operator) { return 0; } - // public static final int Add = 0; - // public static final int Subtract = 26; - // public static final int Multiply = 22; - // public static final int Divide = 9; - // public static final int Concat = 42; - // public static final int Assign = 2; - // public static final int BitwiseAnd = 3; - // public static final int BitwiseNot = 4; - // public static final int BitwiseOr = 5; - // public static final int BitwiseXor = 6; - // public static final int BooleanAnd = 7; - // public static final int BooleanOr = 8; - // public static final int Equality = 10; - // public static final int GreaterThan = 11; - // public static final int GreaterThanOrEqual = 12; - // public static final int Is = 13; - // public static final int LessThan = 14; - // public static final int LessThanOrEqual = 15; - // public static final int LessThanOrGreater = 16; - // public static final int LeftShift = 17; - // public static final int Like = 18; - // public static final int RightShift = 19; - // public static final int Modulus = 21; - // public static final int NotEqual = 23; - // public static final int NotLessThan = 24; - // public static final int NotGreaterThan = 25; - // public static final int Union = 27; - // public static final int NotLike = 40; - // public static final int IsNot = 41; - // public static final int Escape = 43; - // - public final String name; public final int priority; diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlParameterizedOutputVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlParameterizedOutputVisitor.java new file mode 100644 index 0000000000..ae3a4e0789 --- /dev/null +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlParameterizedOutputVisitor.java @@ -0,0 +1,109 @@ +package com.alibaba.druid.sql.dialect.mysql.visitor; + +import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr; +import com.alibaba.druid.sql.ast.expr.SQLInListExpr; +import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr; +import com.alibaba.druid.sql.ast.expr.SQLLiteralExpr; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlInsertStatement; + +public class MySqlParameterizedOutputVisitor extends MySqlOutputVisitor { + + public MySqlParameterizedOutputVisitor(Appendable appender){ + super(appender); + } + + public void println() { + print(' '); + } + + public boolean visit(SQLInListExpr x) { + x.getExpr().accept(this); + + if (x.isNot()) { + print(" NOT IN (##)"); + } else { + print(" IN (##)"); + } + return false; + } + + public boolean visit(SQLBinaryOpExpr x) { + if (x.getLeft() instanceof SQLLiteralExpr && x.getRight() instanceof SQLLiteralExpr) { + print(x.getLeft().toString()); + print(' '); + print(x.getOperator().name); + print(' '); + print(x.getRight().toString()); + return false; + } + + return super.visit(x); + } + + public boolean visit(SQLIntegerExpr x) { + print('?'); + return false; + } + + @Override + public boolean visit(MySqlInsertStatement x) { + print("INSERT "); + + if (x.isLowPriority()) { + print("LOW_PRIORITY "); + } + + if (x.isDelayed()) { + print("DELAYED "); + } + + if (x.isHighPriority()) { + print("HIGH_PRIORITY "); + } + + if (x.isIgnore()) { + print("IGNORE "); + } + + print("INTO "); + + x.getTableName().accept(this); + + if (x.getColumns().size() > 0) { + print(" ("); + for (int i = 0, size = x.getColumns().size(); i < size; ++i) { + if (i != 0) { + print(", "); + } + x.getColumns().get(i).accept(this); + } + print(")"); + } + + if (x.getValuesList().size() != 0) { + print(" VALUES "); + int size = x.getValuesList().size(); + if (size == 0) { + print("()"); + } else { + for (int i = 0; i < 1; ++i) { + if (i != 0) { + print(", "); + } + x.getValuesList().get(i).accept(this); + } + } + } + if (x.getQuery() != null) { + print(" "); + x.getQuery().accept(this); + } + + if (x.getDuplicateKeyUpdate().size() != 0) { + print(" ON DUPLICATE KEY UPDATE "); + printAndAccept(x.getDuplicateKeyUpdate(), ", "); + } + + return false; + } +} diff --git a/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java b/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java index 8209c884f9..1656892f44 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java +++ b/src/main/java/com/alibaba/druid/sql/parser/SQLExprParser.java @@ -650,14 +650,14 @@ public class SQLExprParser extends SQLParser { SQLExpr rightExp; if (lexer.token() == Token.EQ) { lexer.nextToken(); - rightExp = or(); + rightExp = relational(); rightExp = equalityRest(rightExp); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.Equality, rightExp); } else if (lexer.token() == Token.BANGEQ) { lexer.nextToken(); - rightExp = or(); + rightExp = relational(); rightExp = equalityRest(rightExp); @@ -731,13 +731,13 @@ public class SQLExprParser extends SQLParser { public SQLExpr shiftRest(SQLExpr expr) throws ParserException { if (lexer.token() == Token.LTLT) { lexer.nextToken(); - SQLExpr rightExp = multiplicative(); + SQLExpr rightExp = additive(); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.LeftShift, rightExp); expr = shiftRest(expr); } else if (lexer.token() == Token.GTGT) { lexer.nextToken(); - SQLExpr rightExp = multiplicative(); + SQLExpr rightExp = additive(); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.RightShift, rightExp); expr = shiftRest(expr); @@ -747,42 +747,47 @@ public class SQLExprParser extends SQLParser { } public final SQLExpr and() throws ParserException { - SQLExpr expr = equality(); + SQLExpr expr = relational(); return andRest(expr); } public final SQLExpr andRest(SQLExpr expr) throws ParserException { - while (lexer.token() == Token.AND || lexer.token() == Token.AMPAMP) { + if (lexer.token() == Token.AND || lexer.token() == Token.AMPAMP) { lexer.nextToken(); SQLExpr rightExp = equality(); + expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.BooleanAnd, rightExp); + expr = andRest(expr); } + return expr; } public final SQLExpr xor() throws ParserException { - SQLExpr expr = and(); + SQLExpr expr = relational(); return xorRest(expr); } public final SQLExpr xorRest(SQLExpr expr) throws ParserException { - while (lexer.token() == Token.XOR) { + if (lexer.token() == Token.XOR) { lexer.nextToken(); - SQLExpr rightExp = and(); - expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.BooleanXor, rightExp); + SQLExpr rightExp = equality(); + + expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.BooleanAnd, rightExp); + expr = xorRest(expr); } return expr; } public final SQLExpr or() throws ParserException { - SQLExpr expr = xor(); + SQLExpr expr = and(); return orRest(expr); } public final SQLExpr orRest(SQLExpr expr) throws ParserException { while (lexer.token() == Token.OR) { lexer.nextToken(); - SQLExpr rightExp = xor(); + SQLExpr rightExp = and(); expr = new SQLBinaryOpExpr(expr, SQLBinaryOperator.BooleanOr, rightExp); } return expr; @@ -796,6 +801,7 @@ public class SQLExprParser extends SQLParser { public SQLExpr relationalRest(SQLExpr expr) throws ParserException { SQLExpr rightExp; + if (lexer.token() == Token.LT) { lexer.nextToken(); rightExp = bitOr(); diff --git a/src/test/java/com/alibaba/druid/bvt/proxy/CounterFilterTest.java b/src/test/java/com/alibaba/druid/bvt/proxy/CounterFilterTest.java index 2ef5b100b4..beb481e9b4 100644 --- a/src/test/java/com/alibaba/druid/bvt/proxy/CounterFilterTest.java +++ b/src/test/java/com/alibaba/druid/bvt/proxy/CounterFilterTest.java @@ -32,7 +32,6 @@ import com.alibaba.druid.proxy.jdbc.ConnectionProxy; import com.alibaba.druid.proxy.jdbc.DataSourceProxyConfig; import com.alibaba.druid.proxy.jdbc.DataSourceProxyImpl; import com.alibaba.druid.proxy.jdbc.ResultSetProxy; -import com.alibaba.druid.stat.JdbcResultSetStat; public class CounterFilterTest extends TestCase { @@ -86,7 +85,6 @@ public class CounterFilterTest extends TestCase { Statement stmt = conn.createStatement(); ResultSetProxy rs = (ResultSetProxy) stmt.executeQuery(sql); - JdbcResultSetStat.Entry resultSetStat = StatFilter.getResultSetInfo(rs); rs.close(); stmt.close(); diff --git a/src/test/java/com/alibaba/druid/sql/OnlineSQLTest.java b/src/test/java/com/alibaba/druid/sql/OnlineSQLTest.java new file mode 100644 index 0000000000..cbf9b2a7fb --- /dev/null +++ b/src/test/java/com/alibaba/druid/sql/OnlineSQLTest.java @@ -0,0 +1,37 @@ +package com.alibaba.druid.sql; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.Statement; + +import junit.framework.TestCase; + +public class OnlineSQLTest extends TestCase { + private String url = "jdbc:mysql://10.20.129.146/dragoon_v25monitordb_online"; + private String user = "dragoon"; + private String password = "dragoon"; + + + + public void test_list_sql() throws Exception { + Connection conn = DriverManager.getConnection(url, user, password); + + int count = 0; + String sql = "SELECT id, value FROM m_sql_const"; + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery(sql); + while (rs.next()) { + String value = rs.getString(2); + System.out.println(value); + System.out.println(); + count++; + } + rs.close(); + stmt.close(); + + System.out.println("COUNT : " + count); + + conn.close(); + } +} diff --git a/src/test/java/com/alibaba/druid/sql/mysql/bvt/ArithmeticOperatorsTest.java b/src/test/java/com/alibaba/druid/sql/mysql/bvt/ArithmeticOperatorsTest.java index f1557e4ec2..ac9ed03e50 100644 --- a/src/test/java/com/alibaba/druid/sql/mysql/bvt/ArithmeticOperatorsTest.java +++ b/src/test/java/com/alibaba/druid/sql/mysql/bvt/ArithmeticOperatorsTest.java @@ -158,6 +158,28 @@ public class ArithmeticOperatorsTest extends TestCase { Assert.assertEquals("SELECT N % M;", text); } + + public void test_12() throws Exception { + String sql = "SELECT 1 = 0 OR A > ?;"; + + SQLStatementParser parser = new MySqlStatementParser(sql); + List stmtList = parser.parseStatementList(); + + String text = output(stmtList); + + Assert.assertEquals("SELECT 1 = 0 OR A > ?;", text); + } + + public void test_13() throws Exception { + String sql = "SELECT 1 = 0 AND ID = ?;"; + + SQLStatementParser parser = new MySqlStatementParser(sql); + List stmtList = parser.parseStatementList(); + + String text = output(stmtList); + + Assert.assertEquals("SELECT 1 = 0 AND ID = ?;", text); + } private String output(List stmtList) { StringBuilder out = new StringBuilder(); diff --git a/src/test/java/com/alibaba/druid/sql/mysql/bvt/MySqlParameterizedOutputVisitorTest.java b/src/test/java/com/alibaba/druid/sql/mysql/bvt/MySqlParameterizedOutputVisitorTest.java new file mode 100644 index 0000000000..b807577e46 --- /dev/null +++ b/src/test/java/com/alibaba/druid/sql/mysql/bvt/MySqlParameterizedOutputVisitorTest.java @@ -0,0 +1,34 @@ +package com.alibaba.druid.sql.mysql.bvt; + +import java.util.List; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser; +import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlParameterizedOutputVisitor; + +public class MySqlParameterizedOutputVisitorTest extends TestCase { + + public void test_0() throws Exception { + //validate("SELECT * FROM T WHERE ID IN (?, ?, ?)", "SELECT * FROM T WHERE ID IN (##)"); + //validate("SELECT * FROM T WHERE ID = 5", "SELECT * FROM T WHERE ID = ?"); + validate("SELECT * FROM T WHERE 1 = 0 AND ID = 5", "SELECT * FROM T WHERE 1 = 0 AND ID = ?"); + } + + void validate(String sql, String expect) { + + MySqlStatementParser parser = new MySqlStatementParser(sql); + List statementList = parser.parseStatementList(); + SQLStatement statemen = statementList.get(0); + + Assert.assertEquals(1, statementList.size()); + + StringBuilder out = new StringBuilder(); + MySqlParameterizedOutputVisitor visitor = new MySqlParameterizedOutputVisitor(out); + statemen.accept(visitor); + + Assert.assertEquals(expect, out.toString()); + } +}