diff --git a/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSource.java b/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSource.java index d1523683f8..83fa7cfbfc 100644 --- a/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSource.java +++ b/src/main/java/com/alibaba/druid/pool/DruidAbstractDataSource.java @@ -228,6 +228,8 @@ public abstract class DruidAbstractDataSource extends WrapperAdapter implements protected AtomicLong createCount = new AtomicLong(); protected AtomicLong destroyCount = new AtomicLong(); + private Boolean useUnfairLock = null; + public DruidAbstractDataSource(boolean lockFair){ lock = new ReentrantLock(lockFair); @@ -246,6 +248,32 @@ public abstract class DruidAbstractDataSource extends WrapperAdapter implements this.isOracle = isOracle; } + public boolean isUseUnfairLock() { + return lock.isFair(); + } + + public void setUseUnfairLock(boolean useUnfairLock) { + if (lock.isFair() == !useUnfairLock) { + return; + } + + if (!this.inited) { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + if (!this.inited) { + this.lock = new ReentrantLock(!useUnfairLock); + this.notEmpty = this.lock.newCondition(); + this.empty = this.lock.newCondition(); + + this.useUnfairLock = useUnfairLock; + } + } finally { + lock.unlock(); + } + } + } + public boolean isUseOracleImplicitCache() { return useOracleImplicitCache; } @@ -794,7 +822,7 @@ public abstract class DruidAbstractDataSource extends WrapperAdapter implements return; } - if (maxWaitMillis > 0 && !this.inited) { + if (maxWaitMillis > 0 && useUnfairLock == null && !this.inited) { final ReentrantLock lock = this.lock; lock.lock(); try { diff --git a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlLexer.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlLexer.java index a2dbf44073..0938a7d2eb 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlLexer.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/parser/MySqlLexer.java @@ -20,6 +20,7 @@ import static com.alibaba.druid.sql.parser.CharTypes.isIdentifierChar; import static com.alibaba.druid.sql.parser.LayoutCharacters.EOI; import static com.alibaba.druid.sql.parser.Token.LITERAL_CHARS; +import java.util.Arrays; import java.util.HashMap; import java.util.Map; @@ -35,9 +36,9 @@ public class MySqlLexer extends Lexer { static { Map map = new HashMap(); - + map.putAll(Keywords.DEFAULT_KEYWORDS.getKeywords()); - + map.put("DUAL", Token.DUAL); map.put("FALSE", Token.FALSE); map.put("IDENTIFIED", Token.IDENTIFIED); @@ -46,7 +47,7 @@ public class MySqlLexer extends Lexer { map.put("LIMIT", Token.LIMIT); map.put("TRUE", Token.TRUE); - + DEFAULT_MYSQL_KEYWORDS = new Keywords(map); } @@ -97,28 +98,28 @@ public class MySqlLexer extends Lexer { stringVal = subString(mark, bufPos); token = Token.VARIANT; } else if (charAt(pos + 1) == '{') { - ++pos; - ++bufPos; - char ch; - for (;;) { - ch = charAt(++pos); - - if (ch == '}') { - bufPos++; - ch = charAt(++pos); - break; - } else if (ch == EOI) { - throw new SQLParseException("illegal identifier"); - } - + ++pos; + ++bufPos; + char ch; + for (;;) { + ch = charAt(++pos); + + if (ch == '}') { bufPos++; - continue; + ch = charAt(++pos); + break; + } else if (ch == EOI) { + throw new SQLParseException("illegal identifier"); } - - this.ch = charAt(pos); - - stringVal = subString(mark, bufPos); - token = Token.VARIANT; + + bufPos++; + continue; + } + + this.ch = charAt(pos); + + stringVal = subString(mark, bufPos); + token = Token.VARIANT; } else { for (;;) { ch = charAt(++pos); @@ -222,9 +223,7 @@ public class MySqlLexer extends Lexer { if (ch == '\\') { scanChar(); if (!hasSpecial) { - if (buf == null) { - buf = new char[32]; - } + initBuff(bufPos); arraycopy(mark + 1, buf, 0, bufPos); hasSpecial = true; } @@ -270,9 +269,7 @@ public class MySqlLexer extends Lexer { token = LITERAL_CHARS; break; } else { - if (buf == null) { - buf = new char[32]; - } + initBuff(bufPos); arraycopy(mark + 1, buf, 0, bufPos); hasSpecial = true; putChar('\''); @@ -298,7 +295,7 @@ public class MySqlLexer extends Lexer { stringVal = new String(buf, 0, bufPos); } } - + public void scanComment() { if (ch != '/' && ch != '-') { throw new IllegalStateException(); @@ -345,14 +342,14 @@ public class MySqlLexer extends Lexer { stringVal = subString(mark, bufPos); token = Token.MULTI_LINE_COMMENT; } - + if (token != Token.HINT && !isAllowComment()) { throw new NotAllowCommentException(); } return; } - + if (!isAllowComment()) { throw new NotAllowCommentException(); } 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 35343122b6..78f3dacbfc 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 @@ -27,6 +27,7 @@ import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr; import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr; import com.alibaba.druid.sql.ast.expr.SQLNullExpr; import com.alibaba.druid.sql.ast.expr.SQLNumberExpr; +import com.alibaba.druid.sql.ast.expr.SQLQueryExpr; 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; @@ -75,7 +76,7 @@ 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); } @@ -83,38 +84,43 @@ public class MySqlEvalVisitorImpl extends MySqlASTVisitorAdapter implements SQLE 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(SQLBetweenExpr x) { return SQLEvalVisitorUtils.visit(this, x); } - + @Override public boolean visit(SQLInListExpr x) { return SQLEvalVisitorUtils.visit(this, x); } - + @Override public boolean visit(SQLNullExpr x) { return SQLEvalVisitorUtils.visit(this, x); } - + @Override public boolean visit(SQLMethodInvokeExpr x) { return SQLEvalVisitorUtils.visit(this, x); } - + + @Override + public boolean visit(SQLQueryExpr 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/mysql/visitor/MySqlOutputVisitor.java b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlOutputVisitor.java index 955bdb1ac6..20821add4f 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlOutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/mysql/visitor/MySqlOutputVisitor.java @@ -488,7 +488,15 @@ public class MySqlOutputVisitor extends SQLASTOutputVisitor implements MySqlASTV } public boolean visit(SQLCharExpr x) { - print(x.toString()); + print('\''); + + String text = x.getText(); + text = text.replaceAll("'", "''"); + text = text.replaceAll("\\\\", "\\\\"); + + print(text); + + print('\''); return false; } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleSelectParser.java b/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleSelectParser.java index c75a4eabcc..b02fba05bd 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleSelectParser.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/oracle/parser/OracleSelectParser.java @@ -643,6 +643,12 @@ public class OracleSelectParser extends SQLSelectParser { if (identifierEquals("NOCYCLE")) { hierachical.setNoCycle(true); + lexer.nextToken(); + + if (lexer.token() == Token.PRIOR) { + lexer.nextToken(); + hierachical.setPrior(true); + } } hierachical.setConnectBy(this.exprParser.expr()); } @@ -672,6 +678,12 @@ public class OracleSelectParser extends SQLSelectParser { if (identifierEquals("NOCYCLE")) { hierachical.setNoCycle(true); + lexer.nextToken(); + + if (lexer.token() == Token.PRIOR) { + lexer.nextToken(); + hierachical.setPrior(true); + } } hierachical.setConnectBy(this.exprParser.expr()); } 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 2045a881d1..a7f62b49b5 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 @@ -26,6 +26,7 @@ import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr; import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr; import com.alibaba.druid.sql.ast.expr.SQLNullExpr; import com.alibaba.druid.sql.ast.expr.SQLNumberExpr; +import com.alibaba.druid.sql.ast.expr.SQLQueryExpr; import com.alibaba.druid.sql.ast.expr.SQLVariantRefExpr; import com.alibaba.druid.sql.visitor.SQLEvalVisitor; import com.alibaba.druid.sql.visitor.SQLEvalVisitorUtils; @@ -101,7 +102,12 @@ public class OracleEvalVisitor extends OracleASTVisitorAdapter implements SQLEva public boolean visit(SQLMethodInvokeExpr x) { return SQLEvalVisitorUtils.visit(this, x); } - + + @Override + public boolean visit(SQLQueryExpr x) { + return SQLEvalVisitorUtils.visit(this, x); + } + public boolean isMarkVariantIndex() { return markVariantIndex; } diff --git a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGLexer.java b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGLexer.java index a1d8818b60..590caa6016 100644 --- a/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGLexer.java +++ b/src/main/java/com/alibaba/druid/sql/dialect/postgresql/parser/PGLexer.java @@ -84,9 +84,7 @@ public class PGLexer extends Lexer { if (ch == '\\') { scanChar(); if (!hasSpecial) { - if (buf == null) { - buf = new char[32]; - } + initBuff(bufPos); arraycopy(mark + 1, buf, 0, bufPos); hasSpecial = true; } @@ -132,6 +130,7 @@ public class PGLexer extends Lexer { token = LITERAL_CHARS; break; } else { + initBuff(bufPos); arraycopy(mark + 1, buf, 0, bufPos); hasSpecial = true; putChar('\''); 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 f4d0d1fe60..6e590d4b84 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 @@ -26,6 +26,7 @@ import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr; import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr; import com.alibaba.druid.sql.ast.expr.SQLNullExpr; import com.alibaba.druid.sql.ast.expr.SQLNumberExpr; +import com.alibaba.druid.sql.ast.expr.SQLQueryExpr; import com.alibaba.druid.sql.ast.expr.SQLVariantRefExpr; import com.alibaba.druid.sql.visitor.SQLEvalVisitor; import com.alibaba.druid.sql.visitor.SQLEvalVisitorUtils; @@ -81,7 +82,7 @@ public class PGEvalVisitor extends PGASTVisitorAdapter implements SQLEvalVisitor public boolean visit(SQLNumberExpr x) { return SQLEvalVisitorUtils.visit(this, x); } - + @Override public boolean visit(SQLCaseExpr x) { return SQLEvalVisitorUtils.visit(this, x); @@ -101,7 +102,12 @@ public class PGEvalVisitor extends PGASTVisitorAdapter implements SQLEvalVisitor public boolean visit(SQLMethodInvokeExpr x) { return SQLEvalVisitorUtils.visit(this, x); } - + + @Override + public boolean visit(SQLQueryExpr x) { + return SQLEvalVisitorUtils.visit(this, x); + } + public boolean isMarkVariantIndex() { return markVariantIndex; } diff --git a/src/main/java/com/alibaba/druid/sql/parser/Lexer.java b/src/main/java/com/alibaba/druid/sql/parser/Lexer.java index 11ccfc2ce0..965aeb2c72 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/Lexer.java +++ b/src/main/java/com/alibaba/druid/sql/parser/Lexer.java @@ -34,6 +34,7 @@ import static com.alibaba.druid.sql.parser.Token.RPAREN; import java.math.BigDecimal; import java.math.BigInteger; +import java.util.Arrays; /** * @author wenshao @@ -85,6 +86,18 @@ public class Lexer { public final String subString(int offset, int count) { return text.substring(offset, offset + count); } + + protected void initBuff(int size) { + if (buf == null) { + if (size < 32) { + buf = new char[32]; + } else { + buf = new char[size + 32]; + } + } else if(buf.length < size) { + buf = Arrays.copyOf(buf, size); + } + } public void arraycopy(int srcPos, char[] dest, int destPos, int length) { text.getChars(srcPos, srcPos + length, dest, destPos); @@ -494,9 +507,7 @@ public class Lexer { break; } else { if (!hasSpecial) { - if (buf == null) { - buf = new char[32]; - } + initBuff(bufPos); arraycopy(mark + 1, buf, 0, bufPos); hasSpecial = true; } diff --git a/src/main/java/com/alibaba/druid/sql/parser/SQLSelectParser.java b/src/main/java/com/alibaba/druid/sql/parser/SQLSelectParser.java index f758edd7c2..9bb086c199 100644 --- a/src/main/java/com/alibaba/druid/sql/parser/SQLSelectParser.java +++ b/src/main/java/com/alibaba/druid/sql/parser/SQLSelectParser.java @@ -306,6 +306,10 @@ public class SQLSelectParser extends SQLParser { } else if (identifierEquals("STRAIGHT_JOIN")) { lexer.nextToken(); joinType = SQLJoinTableSource.JoinType.STRAIGHT_JOIN; + } else if (identifierEquals("CROSS")) { + lexer.nextToken(); + accept(Token.JOIN); + joinType = SQLJoinTableSource.JoinType.CROSS_JOIN; } if (joinType != null) { 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 658f336a38..38ce1f2b70 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SQLASTOutputVisitor.java @@ -97,8 +97,9 @@ import com.alibaba.druid.sql.ast.statement.SQLUseStatement; public class SQLASTOutputVisitor extends SQLASTVisitorAdapter { protected final Appendable appender; - private String indent = "\t"; - private int indentCount = 0; + private String indent = "\t"; + private int indentCount = 0; + private boolean prettyFormat = true; public SQLASTOutputVisitor(Appendable appender){ this.appender = appender; @@ -112,6 +113,14 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter { return appender; } + public boolean isPrettyFormat() { + return prettyFormat; + } + + public void setPrettyFormat(boolean prettyFormat) { + this.prettyFormat = prettyFormat; + } + public void decrementIndent() { this.indentCount -= 1; } @@ -193,6 +202,11 @@ public class SQLASTOutputVisitor extends SQLASTVisitorAdapter { } public void println() { + if (!isPrettyFormat()) { + print(' '); + return; + } + print("\n"); printIndent(); } 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 efd250209a..576dbb1063 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SQLEvalVisitorImpl.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SQLEvalVisitorImpl.java @@ -26,6 +26,7 @@ import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr; import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr; import com.alibaba.druid.sql.ast.expr.SQLNullExpr; import com.alibaba.druid.sql.ast.expr.SQLNumberExpr; +import com.alibaba.druid.sql.ast.expr.SQLQueryExpr; import com.alibaba.druid.sql.ast.expr.SQLVariantRefExpr; public class SQLEvalVisitorImpl extends SQLASTVisitorAdapter implements SQLEvalVisitor { @@ -79,7 +80,7 @@ public class SQLEvalVisitorImpl extends SQLASTVisitorAdapter implements SQLEvalV public boolean visit(SQLNumberExpr x) { return SQLEvalVisitorUtils.visit(this, x); } - + @Override public boolean visit(SQLCaseExpr x) { return SQLEvalVisitorUtils.visit(this, x); @@ -99,7 +100,12 @@ public class SQLEvalVisitorImpl extends SQLASTVisitorAdapter implements SQLEvalV public boolean visit(SQLMethodInvokeExpr x) { return SQLEvalVisitorUtils.visit(this, x); } - + + @Override + public boolean visit(SQLQueryExpr 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 8489a3b9ca..4b08cbf15a 100644 --- a/src/main/java/com/alibaba/druid/sql/visitor/SQLEvalVisitorUtils.java +++ b/src/main/java/com/alibaba/druid/sql/visitor/SQLEvalVisitorUtils.java @@ -21,10 +21,12 @@ import java.math.BigDecimal; import java.math.BigInteger; import java.text.ParseException; import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.List; import java.util.Map; +import java.util.regex.Pattern; import com.alibaba.druid.DruidRuntimeException; import com.alibaba.druid.sql.SQLUtils; @@ -34,11 +36,16 @@ import com.alibaba.druid.sql.ast.expr.SQLBetweenExpr; 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.SQLIdentifierExpr; import com.alibaba.druid.sql.ast.expr.SQLInListExpr; import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr; import com.alibaba.druid.sql.ast.expr.SQLNullExpr; import com.alibaba.druid.sql.ast.expr.SQLNumericLiteralExpr; +import com.alibaba.druid.sql.ast.expr.SQLQueryExpr; import com.alibaba.druid.sql.ast.expr.SQLVariantRefExpr; +import com.alibaba.druid.sql.ast.statement.SQLExprTableSource; +import com.alibaba.druid.sql.ast.statement.SQLSelectItem; +import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock; import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlEvalVisitorImpl; import com.alibaba.druid.sql.dialect.oracle.visitor.OracleEvalVisitor; import com.alibaba.druid.sql.dialect.postgresql.visitor.PGEvalVisitor; @@ -106,24 +113,512 @@ public class SQLEvalVisitorUtils { return new SQLEvalVisitorImpl(); } - + public static boolean visit(SQLEvalVisitor visitor, SQLMethodInvokeExpr x) { - if ("concat".equals(x.getMethodName())) { + if ("concat".equalsIgnoreCase(x.getMethodName())) { StringBuilder buf = new StringBuilder(); - + for (SQLExpr item : x.getParameters()) { item.accept(visitor); - + Object itemValue = item.getAttributes().get(EVAL_VALUE); if (itemValue == null) { continue; } buf.append(itemValue.toString()); } - + x.getAttributes().put(EVAL_VALUE, buf.toString()); - } else if ("now".equals(x.getMethodName())) { + } else if ("now".equalsIgnoreCase(x.getMethodName())) { x.getAttributes().put(EVAL_VALUE, new Date()); + } else if ("ascii".equalsIgnoreCase(x.getMethodName())) { + if (x.getParameters().size() == 0) { + return false; + } + SQLExpr param = x.getParameters().get(0); + param.accept(visitor); + + Object paramValue = param.getAttributes().get(EVAL_VALUE); + if (paramValue == null) { + return false; + } + + String strValue = paramValue.toString(); + if (strValue.length() == 0) { + return false; + } + + int ascii = strValue.charAt(0); + x.getAttributes().put(EVAL_VALUE, ascii); + } else if ("instr".equalsIgnoreCase(x.getMethodName())) { + if (x.getParameters().size() != 2) { + return false; + } + + SQLExpr param0 = x.getParameters().get(0); + SQLExpr param1 = x.getParameters().get(1); + param0.accept(visitor); + param1.accept(visitor); + + Object param0Value = param0.getAttributes().get(EVAL_VALUE); + Object param1Value = param1.getAttributes().get(EVAL_VALUE); + if (param0Value == null || param1Value == null) { + return false; + } + + String strValue0 = param0Value.toString(); + String strValue1 = param1Value.toString(); + + int result = strValue0.indexOf(strValue1) + 1; + + x.putAttribute(EVAL_VALUE, result); + } else if ("left".equalsIgnoreCase(x.getMethodName())) { + if (x.getParameters().size() != 2) { + return false; + } + + SQLExpr param0 = x.getParameters().get(0); + SQLExpr param1 = x.getParameters().get(1); + param0.accept(visitor); + param1.accept(visitor); + + Object param0Value = param0.getAttributes().get(EVAL_VALUE); + Object param1Value = param1.getAttributes().get(EVAL_VALUE); + if (param0Value == null || param1Value == null) { + return false; + } + + String strValue = param0Value.toString(); + int intValue = _int(param1Value); + + String result = strValue.substring(0, intValue); + + x.putAttribute(EVAL_VALUE, result); + } else if ("right".equalsIgnoreCase(x.getMethodName())) { + if (x.getParameters().size() != 2) { + return false; + } + + SQLExpr param0 = x.getParameters().get(0); + SQLExpr param1 = x.getParameters().get(1); + param0.accept(visitor); + param1.accept(visitor); + + Object param0Value = param0.getAttributes().get(EVAL_VALUE); + Object param1Value = param1.getAttributes().get(EVAL_VALUE); + if (param0Value == null || param1Value == null) { + return false; + } + + String strValue = param0Value.toString(); + int intValue = _int(param1Value); + + String result = strValue.substring(strValue.length() - intValue, strValue.length()); + + x.putAttribute(EVAL_VALUE, result); + } else if ("reverse".equalsIgnoreCase(x.getMethodName())) { + if (x.getParameters().size() != 1) { + return false; + } + + SQLExpr param0 = x.getParameters().get(0); + param0.accept(visitor); + + Object param0Value = param0.getAttributes().get(EVAL_VALUE); + if (param0Value == null) { + return false; + } + + String strValue = param0Value.toString(); + + StringBuilder buf = new StringBuilder(); + for (int i = strValue.length() - 1; i >= 0; --i) { + buf.append(strValue.charAt(i)); + } + String result = buf.toString(); + + x.putAttribute(EVAL_VALUE, result); + } else if ("trim".equalsIgnoreCase(x.getMethodName())) { + if (x.getParameters().size() != 1) { + return false; + } + + SQLExpr param0 = x.getParameters().get(0); + param0.accept(visitor); + + Object param0Value = param0.getAttributes().get(EVAL_VALUE); + if (param0Value == null) { + return false; + } + + String strValue = param0Value.toString(); + String result = strValue.trim(); + + x.putAttribute(EVAL_VALUE, result); + } else if ("length".equalsIgnoreCase(x.getMethodName())) { + if (x.getParameters().size() != 1) { + return false; + } + + SQLExpr param0 = x.getParameters().get(0); + param0.accept(visitor); + + Object param0Value = param0.getAttributes().get(EVAL_VALUE); + if (param0Value == null) { + return false; + } + + String strValue = param0Value.toString(); + + int result = strValue.length(); + + x.putAttribute(EVAL_VALUE, result); + } else if ("ucase".equalsIgnoreCase(x.getMethodName()) || "upper".equalsIgnoreCase(x.getMethodName())) { + if (x.getParameters().size() != 1) { + return false; + } + + SQLExpr param0 = x.getParameters().get(0); + param0.accept(visitor); + + Object param0Value = param0.getAttributes().get(EVAL_VALUE); + if (param0Value == null) { + return false; + } + + String strValue = param0Value.toString(); + + String result = strValue.toUpperCase(); + + x.putAttribute(EVAL_VALUE, result); + } else if ("lcase".equalsIgnoreCase(x.getMethodName()) || "lower".equalsIgnoreCase(x.getMethodName())) { + if (x.getParameters().size() != 1) { + return false; + } + + SQLExpr param0 = x.getParameters().get(0); + param0.accept(visitor); + + Object param0Value = param0.getAttributes().get(EVAL_VALUE); + if (param0Value == null) { + return false; + } + + String strValue = param0Value.toString(); + + String result = strValue.toLowerCase(); + + x.putAttribute(EVAL_VALUE, result); + + } else if ("mod".equalsIgnoreCase(x.getMethodName())) { + if (x.getParameters().size() != 2) { + return false; + } + + SQLExpr param0 = x.getParameters().get(0); + SQLExpr param1 = x.getParameters().get(1); + param0.accept(visitor); + param1.accept(visitor); + + Object param0Value = param0.getAttributes().get(EVAL_VALUE); + Object param1Value = param1.getAttributes().get(EVAL_VALUE); + if (param0Value == null || param1Value == null) { + return false; + } + + int intValue0 = _int(param0Value); + int intValue1 = _int(param1Value); + + int result = intValue0 % intValue1; + + x.putAttribute(EVAL_VALUE, result); + } else if ("abs".equalsIgnoreCase(x.getMethodName())) { + if (x.getParameters().size() != 1) { + return false; + } + + SQLExpr param0 = x.getParameters().get(0); + param0.accept(visitor); + + Object paramValue = param0.getAttributes().get(EVAL_VALUE); + if (paramValue == null) { + return false; + } + + Object result; + if (paramValue instanceof Integer) { + result = Math.abs(((Integer) paramValue).intValue()); + } else if (paramValue instanceof Long) { + result = Math.abs(((Long) paramValue).longValue()); + } else { + result = _decimal(paramValue).abs(); + } + + x.putAttribute(EVAL_VALUE, result); + } else if ("acos".equalsIgnoreCase(x.getMethodName())) { + if (x.getParameters().size() != 1) { + return false; + } + + SQLExpr param0 = x.getParameters().get(0); + param0.accept(visitor); + + Object paramValue = param0.getAttributes().get(EVAL_VALUE); + if (paramValue == null) { + return false; + } + + double doubleValue = _double(paramValue); + double result = Math.acos(doubleValue); + + if (Double.isNaN(result)) { + x.putAttribute(EVAL_VALUE, null); + } else { + x.putAttribute(EVAL_VALUE, result); + } + } else if ("asin".equalsIgnoreCase(x.getMethodName())) { + if (x.getParameters().size() != 1) { + return false; + } + + SQLExpr param0 = x.getParameters().get(0); + param0.accept(visitor); + + Object paramValue = param0.getAttributes().get(EVAL_VALUE); + if (paramValue == null) { + return false; + } + + double doubleValue = _double(paramValue); + double result = Math.asin(doubleValue); + + if (Double.isNaN(result)) { + x.putAttribute(EVAL_VALUE, null); + } else { + x.putAttribute(EVAL_VALUE, result); + } + } else if ("atan".equalsIgnoreCase(x.getMethodName())) { + if (x.getParameters().size() != 1) { + return false; + } + + SQLExpr param0 = x.getParameters().get(0); + param0.accept(visitor); + + Object paramValue = param0.getAttributes().get(EVAL_VALUE); + if (paramValue == null) { + return false; + } + + double doubleValue = _double(paramValue); + double result = Math.atan(doubleValue); + + if (Double.isNaN(result)) { + x.putAttribute(EVAL_VALUE, null); + } else { + x.putAttribute(EVAL_VALUE, result); + } + } else if ("atan2".equalsIgnoreCase(x.getMethodName())) { + if (x.getParameters().size() != 2) { + return false; + } + + SQLExpr param0 = x.getParameters().get(0); + SQLExpr param1 = x.getParameters().get(1); + param0.accept(visitor); + param1.accept(visitor); + + Object param0Value = param0.getAttributes().get(EVAL_VALUE); + Object param1Value = param1.getAttributes().get(EVAL_VALUE); + if (param0Value == null || param1Value == null) { + return false; + } + + double doubleValue0 = _double(param0Value); + double doubleValue1 = _double(param1Value); + double result = Math.atan2(doubleValue0, doubleValue1); + + if (Double.isNaN(result)) { + x.putAttribute(EVAL_VALUE, null); + } else { + x.putAttribute(EVAL_VALUE, result); + } + } else if ("ceil".equalsIgnoreCase(x.getMethodName()) || "ceiling".equalsIgnoreCase(x.getMethodName())) { + if (x.getParameters().size() != 1) { + return false; + } + + SQLExpr param0 = x.getParameters().get(0); + param0.accept(visitor); + + Object paramValue = param0.getAttributes().get(EVAL_VALUE); + if (paramValue == null) { + return false; + } + + double doubleValue = _double(paramValue); + int result = (int) Math.ceil(doubleValue); + + if (Double.isNaN(result)) { + x.putAttribute(EVAL_VALUE, null); + } else { + x.putAttribute(EVAL_VALUE, result); + } + } else if ("cos".equalsIgnoreCase(x.getMethodName())) { + if (x.getParameters().size() != 1) { + return false; + } + + SQLExpr param0 = x.getParameters().get(0); + param0.accept(visitor); + + Object paramValue = param0.getAttributes().get(EVAL_VALUE); + if (paramValue == null) { + return false; + } + + double doubleValue = _double(paramValue); + int result = (int) Math.cos(doubleValue); + + if (Double.isNaN(result)) { + x.putAttribute(EVAL_VALUE, null); + } else { + x.putAttribute(EVAL_VALUE, result); + } + } else if ("sin".equalsIgnoreCase(x.getMethodName())) { + if (x.getParameters().size() != 1) { + return false; + } + + SQLExpr param0 = x.getParameters().get(0); + param0.accept(visitor); + + Object paramValue = param0.getAttributes().get(EVAL_VALUE); + if (paramValue == null) { + return false; + } + + double doubleValue = _double(paramValue); + int result = (int) Math.sin(doubleValue); + + if (Double.isNaN(result)) { + x.putAttribute(EVAL_VALUE, null); + } else { + x.putAttribute(EVAL_VALUE, result); + } + } else if ("log".equalsIgnoreCase(x.getMethodName())) { + if (x.getParameters().size() != 1) { + return false; + } + + SQLExpr param0 = x.getParameters().get(0); + param0.accept(visitor); + + Object paramValue = param0.getAttributes().get(EVAL_VALUE); + if (paramValue == null) { + return false; + } + + double doubleValue = _double(paramValue); + int result = (int) Math.log(doubleValue); + + if (Double.isNaN(result)) { + x.putAttribute(EVAL_VALUE, null); + } else { + x.putAttribute(EVAL_VALUE, result); + } + } else if ("log10".equalsIgnoreCase(x.getMethodName())) { + if (x.getParameters().size() != 1) { + return false; + } + + SQLExpr param0 = x.getParameters().get(0); + param0.accept(visitor); + + Object paramValue = param0.getAttributes().get(EVAL_VALUE); + if (paramValue == null) { + return false; + } + + double doubleValue = _double(paramValue); + int result = (int) Math.log10(doubleValue); + + if (Double.isNaN(result)) { + x.putAttribute(EVAL_VALUE, null); + } else { + x.putAttribute(EVAL_VALUE, result); + } + } else if ("tan".equalsIgnoreCase(x.getMethodName())) { + if (x.getParameters().size() != 1) { + return false; + } + + SQLExpr param0 = x.getParameters().get(0); + param0.accept(visitor); + + Object paramValue = param0.getAttributes().get(EVAL_VALUE); + if (paramValue == null) { + return false; + } + + double doubleValue = _double(paramValue); + int result = (int) Math.tan(doubleValue); + + if (Double.isNaN(result)) { + x.putAttribute(EVAL_VALUE, null); + } else { + x.putAttribute(EVAL_VALUE, result); + } + } else if ("sqrt".equalsIgnoreCase(x.getMethodName())) { + if (x.getParameters().size() != 1) { + return false; + } + + SQLExpr param0 = x.getParameters().get(0); + param0.accept(visitor); + + Object paramValue = param0.getAttributes().get(EVAL_VALUE); + if (paramValue == null) { + return false; + } + + double doubleValue = _double(paramValue); + int result = (int) Math.sqrt(doubleValue); + + if (Double.isNaN(result)) { + x.putAttribute(EVAL_VALUE, null); + } else { + x.putAttribute(EVAL_VALUE, result); + } + } else if ("power".equalsIgnoreCase(x.getMethodName())) { + if (x.getParameters().size() != 2) { + return false; + } + + SQLExpr param0 = x.getParameters().get(0); + SQLExpr param1 = x.getParameters().get(1); + param0.accept(visitor); + param1.accept(visitor); + + Object param0Value = param0.getAttributes().get(EVAL_VALUE); + Object param1Value = param1.getAttributes().get(EVAL_VALUE); + if (param0Value == null || param1Value == null) { + return false; + } + + double doubleValue0 = _double(param0Value); + double doubleValue1 = _double(param1Value); + double result = Math.pow(doubleValue0, doubleValue1); + + if (Double.isNaN(result)) { + x.putAttribute(EVAL_VALUE, null); + } else { + x.putAttribute(EVAL_VALUE, result); + } + } else if ("pi".equalsIgnoreCase(x.getMethodName())) { + x.putAttribute(EVAL_VALUE, Math.PI); + } else if ("rand".equalsIgnoreCase(x.getMethodName())) { + x.putAttribute(EVAL_VALUE, Math.random()); } return false; } @@ -132,35 +627,35 @@ public class SQLEvalVisitorUtils { x.putAttribute(EVAL_VALUE, x.getText()); return true; } - + public static boolean visit(SQLEvalVisitor visitor, SQLBetweenExpr x) { x.getTestExpr().accept(visitor); - + if (!x.getTestExpr().getAttributes().containsKey(EVAL_VALUE)) { return false; } Object value = x.getTestExpr().getAttribute(EVAL_VALUE); - + x.getBeginExpr().accept(visitor); if (!x.getBeginExpr().getAttributes().containsKey(EVAL_VALUE)) { return false; } Object begin = x.getBeginExpr().getAttribute(EVAL_VALUE); - + if (lt(value, begin)) { x.getAttributes().put(EVAL_VALUE, x.isNot() ? true : false); return false; } - + x.getEndExpr().accept(visitor); if (!x.getEndExpr().getAttributes().containsKey(EVAL_VALUE)) { return false; } Object end = x.getEndExpr().getAttribute(EVAL_VALUE); - + if (gt(value, end)) { x.getAttributes().put(EVAL_VALUE, x.isNot() ? true : false); return false; @@ -169,21 +664,26 @@ public class SQLEvalVisitorUtils { x.getAttributes().put(EVAL_VALUE, x.isNot() ? false : true); return false; } - + public static boolean visit(SQLEvalVisitor visitor, SQLNullExpr x) { x.getAttributes().put(EVAL_VALUE, null); return false; } public static boolean visit(SQLEvalVisitor visitor, SQLCaseExpr x) { - x.getValueExpr().accept(visitor); + Object value; + if (x.getValueExpr() != null) { + x.getValueExpr().accept(visitor); - if (!x.getValueExpr().getAttributes().containsKey(EVAL_VALUE)) { - return false; + if (!x.getValueExpr().getAttributes().containsKey(EVAL_VALUE)) { + return false; + } + + value = x.getValueExpr().getAttribute(EVAL_VALUE); + } else { + value = null; } - Object value = x.getValueExpr().getAttribute(EVAL_VALUE); - for (SQLCaseExpr.Item item : x.getItems()) { item.getConditionExpr().accept(visitor); @@ -214,7 +714,7 @@ public class SQLEvalVisitorUtils { return false; } - + public static boolean visit(SQLEvalVisitor visitor, SQLInListExpr x) { SQLExpr valueExpr = x.getExpr(); valueExpr.accept(visitor); @@ -222,7 +722,7 @@ public class SQLEvalVisitorUtils { return false; } Object value = valueExpr.getAttribute(EVAL_VALUE); - + for (SQLExpr item : x.getTargetList()) { item.accept(visitor); if (!item.getAttributes().containsKey(EVAL_VALUE)) { @@ -234,20 +734,59 @@ public class SQLEvalVisitorUtils { return false; } } - + x.getAttributes().put(EVAL_VALUE, x.isNot() ? true : false); return false; } - + + public static boolean visit(SQLEvalVisitor visitor, SQLQueryExpr x) { + if (x.getSubQuery().getQuery() instanceof SQLSelectQueryBlock) { + SQLSelectQueryBlock queryBlock = (SQLSelectQueryBlock) x.getSubQuery().getQuery(); + + boolean nullFrom = false; + if (queryBlock.getFrom() == null) { + nullFrom = true; + } else if (queryBlock.getFrom() instanceof SQLExprTableSource) { + SQLExpr expr = ((SQLExprTableSource) queryBlock.getFrom()).getExpr(); + if (expr instanceof SQLIdentifierExpr) { + if ("dual".equalsIgnoreCase(((SQLIdentifierExpr) expr).getName())) { + nullFrom = true; + } + } + } + + if (nullFrom) { + List row = new ArrayList(queryBlock.getSelectList().size()); + for (int i = 0; i < queryBlock.getSelectList().size(); ++i) { + SQLSelectItem item = queryBlock.getSelectList().get(i); + item.getExpr().accept(visitor); + Object cell = item.getExpr().getAttribute(EVAL_VALUE); + row.add(cell); + } + List> rows = new ArrayList>(1); + rows.add(row); + + Object result = rows; + queryBlock.putAttribute(EVAL_VALUE, result); + x.getSubQuery().putAttribute(EVAL_VALUE, result); + x.putAttribute(EVAL_VALUE, result); + + return false; + } + } + + return false; + } + public static boolean visit(SQLEvalVisitor visitor, SQLBinaryOpExpr x) { SQLExpr left = x.getLeft(); SQLExpr right = x.getRight(); - + left.accept(visitor); if (!left.getAttributes().containsKey(EVAL_VALUE)) { return false; } - + right.accept(visitor); if (!right.getAttributes().containsKey(EVAL_VALUE)) { return false; @@ -295,6 +834,22 @@ public class SQLEvalVisitorUtils { value = !eq(left.getAttribute(EVAL_VALUE), right.getAttributes().get(EVAL_VALUE)); x.putAttribute(EVAL_VALUE, value); break; + case RegExp: + case RLike: { + String pattern = _string(right.getAttributes().get(EVAL_VALUE)); + String input = _string(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)); + boolean matchResult = !Pattern.matches(pattern, input); + x.putAttribute(EVAL_VALUE, matchResult); + } + break; default: break; } diff --git a/src/main/java/com/alibaba/druid/util/JdbcConstants.java b/src/main/java/com/alibaba/druid/util/JdbcConstants.java index d7b2a59cbd..20f0c4c066 100644 --- a/src/main/java/com/alibaba/druid/util/JdbcConstants.java +++ b/src/main/java/com/alibaba/druid/util/JdbcConstants.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.util; public interface JdbcConstants { diff --git a/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalMethodAbsTest.java b/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalMethodAbsTest.java new file mode 100644 index 0000000000..f434bca1cb --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalMethodAbsTest.java @@ -0,0 +1,15 @@ +package com.alibaba.druid.bvt.sql.eval; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import com.alibaba.druid.sql.visitor.SQLEvalVisitorUtils; +import com.alibaba.druid.util.JdbcConstants; + + +public class EvalMethodAbsTest extends TestCase { + public void test_reverse() throws Exception { + Assert.assertEquals(12, SQLEvalVisitorUtils.evalExpr(JdbcConstants.MYSQL, "abs(-12)")); + Assert.assertEquals(12, SQLEvalVisitorUtils.evalExpr(JdbcConstants.MYSQL, "abs(12)")); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalMethodAcosTest.java b/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalMethodAcosTest.java new file mode 100644 index 0000000000..5cd4fee34c --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalMethodAcosTest.java @@ -0,0 +1,16 @@ +package com.alibaba.druid.bvt.sql.eval; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import com.alibaba.druid.sql.visitor.SQLEvalVisitorUtils; +import com.alibaba.druid.util.JdbcConstants; + + +public class EvalMethodAcosTest extends TestCase { + public void test_reverse() throws Exception { + Assert.assertEquals(0.0D, SQLEvalVisitorUtils.evalExpr(JdbcConstants.MYSQL, "acos(1)")); + Assert.assertEquals(null, SQLEvalVisitorUtils.evalExpr(JdbcConstants.MYSQL, "acos(1.001)")); + Assert.assertEquals(Math.acos(0), SQLEvalVisitorUtils.evalExpr(JdbcConstants.MYSQL, "acos(0)")); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalMethodAsciiTest.java b/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalMethodAsciiTest.java new file mode 100644 index 0000000000..53402b40c3 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalMethodAsciiTest.java @@ -0,0 +1,14 @@ +package com.alibaba.druid.bvt.sql.eval; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import com.alibaba.druid.sql.visitor.SQLEvalVisitorUtils; +import com.alibaba.druid.util.JdbcConstants; + + +public class EvalMethodAsciiTest extends TestCase { + public void test_ascii() throws Exception { + Assert.assertEquals(50, SQLEvalVisitorUtils.evalExpr(JdbcConstants.MYSQL, "ascii('2')")); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalMethodAsinTest.java b/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalMethodAsinTest.java new file mode 100644 index 0000000000..645b7e032d --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalMethodAsinTest.java @@ -0,0 +1,14 @@ +package com.alibaba.druid.bvt.sql.eval; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import com.alibaba.druid.sql.visitor.SQLEvalVisitorUtils; +import com.alibaba.druid.util.JdbcConstants; + + +public class EvalMethodAsinTest extends TestCase { + public void test_reverse() throws Exception { + Assert.assertEquals(Math.asin(0.2), SQLEvalVisitorUtils.evalExpr(JdbcConstants.MYSQL, "asin(0.2)")); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalMethodAtan2Test.java b/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalMethodAtan2Test.java new file mode 100644 index 0000000000..a692518318 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalMethodAtan2Test.java @@ -0,0 +1,14 @@ +package com.alibaba.druid.bvt.sql.eval; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import com.alibaba.druid.sql.visitor.SQLEvalVisitorUtils; +import com.alibaba.druid.util.JdbcConstants; + + +public class EvalMethodAtan2Test extends TestCase { + public void test_reverse() throws Exception { + Assert.assertEquals(Math.atan2(-2, 2), SQLEvalVisitorUtils.evalExpr(JdbcConstants.MYSQL, "atan2(-2, 2)")); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalMethodAtanTest.java b/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalMethodAtanTest.java new file mode 100644 index 0000000000..127eada122 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalMethodAtanTest.java @@ -0,0 +1,15 @@ +package com.alibaba.druid.bvt.sql.eval; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import com.alibaba.druid.sql.visitor.SQLEvalVisitorUtils; +import com.alibaba.druid.util.JdbcConstants; + + +public class EvalMethodAtanTest extends TestCase { + public void test_reverse() throws Exception { + Assert.assertEquals(Math.atan(2), SQLEvalVisitorUtils.evalExpr(JdbcConstants.MYSQL, "atan(2)")); + Assert.assertEquals(Math.atan(-2), SQLEvalVisitorUtils.evalExpr(JdbcConstants.MYSQL, "atan(-2)")); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalMethodCeilTest.java b/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalMethodCeilTest.java new file mode 100644 index 0000000000..e65e982f0e --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalMethodCeilTest.java @@ -0,0 +1,16 @@ +package com.alibaba.druid.bvt.sql.eval; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import com.alibaba.druid.sql.visitor.SQLEvalVisitorUtils; +import com.alibaba.druid.util.JdbcConstants; + + +public class EvalMethodCeilTest extends TestCase { + public void test_reverse() throws Exception { + Assert.assertEquals(2, SQLEvalVisitorUtils.evalExpr(JdbcConstants.MYSQL, "ceil(1.23)")); + Assert.assertEquals(-1, SQLEvalVisitorUtils.evalExpr(JdbcConstants.MYSQL, "ceil(-1.23)")); + Assert.assertEquals(-1, SQLEvalVisitorUtils.evalExpr(JdbcConstants.MYSQL, "ceiling(-1.24)")); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalMethodInstrTest.java b/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalMethodInstrTest.java new file mode 100644 index 0000000000..d9168d860d --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalMethodInstrTest.java @@ -0,0 +1,15 @@ +package com.alibaba.druid.bvt.sql.eval; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import com.alibaba.druid.sql.visitor.SQLEvalVisitorUtils; +import com.alibaba.druid.util.JdbcConstants; + + +public class EvalMethodInstrTest extends TestCase { + public void test_length() throws Exception { + Assert.assertEquals(4, SQLEvalVisitorUtils.evalExpr(JdbcConstants.MYSQL, "instr('foobarbar', 'bar')")); + Assert.assertEquals(0, SQLEvalVisitorUtils.evalExpr(JdbcConstants.MYSQL, "instr('xbar', 'foobar')")); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalMethodLeftTest.java b/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalMethodLeftTest.java new file mode 100644 index 0000000000..e38fca24a8 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalMethodLeftTest.java @@ -0,0 +1,14 @@ +package com.alibaba.druid.bvt.sql.eval; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import com.alibaba.druid.sql.visitor.SQLEvalVisitorUtils; +import com.alibaba.druid.util.JdbcConstants; + + +public class EvalMethodLeftTest extends TestCase { + public void test_ascii() throws Exception { + Assert.assertEquals("fooba", SQLEvalVisitorUtils.evalExpr(JdbcConstants.MYSQL, "LEFT('foobarbar', 5)")); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalMethodLengthTest.java b/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalMethodLengthTest.java new file mode 100644 index 0000000000..74f44e2712 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalMethodLengthTest.java @@ -0,0 +1,14 @@ +package com.alibaba.druid.bvt.sql.eval; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import com.alibaba.druid.sql.visitor.SQLEvalVisitorUtils; +import com.alibaba.druid.util.JdbcConstants; + + +public class EvalMethodLengthTest extends TestCase { + public void test_length() throws Exception { + Assert.assertEquals(4, SQLEvalVisitorUtils.evalExpr(JdbcConstants.MYSQL, "length('text')")); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalMethodModTest.java b/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalMethodModTest.java new file mode 100644 index 0000000000..41dbeeeb91 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalMethodModTest.java @@ -0,0 +1,14 @@ +package com.alibaba.druid.bvt.sql.eval; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import com.alibaba.druid.sql.visitor.SQLEvalVisitorUtils; +import com.alibaba.druid.util.JdbcConstants; + + +public class EvalMethodModTest extends TestCase { + public void test_reverse() throws Exception { + Assert.assertEquals(2, SQLEvalVisitorUtils.evalExpr(JdbcConstants.MYSQL, "MOD(29,9)")); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalMethodPITest.java b/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalMethodPITest.java new file mode 100644 index 0000000000..b1a58c65a9 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalMethodPITest.java @@ -0,0 +1,14 @@ +package com.alibaba.druid.bvt.sql.eval; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import com.alibaba.druid.sql.visitor.SQLEvalVisitorUtils; +import com.alibaba.druid.util.JdbcConstants; + + +public class EvalMethodPITest extends TestCase { + public void test_reverse() throws Exception { + Assert.assertEquals(Math.PI, SQLEvalVisitorUtils.evalExpr(JdbcConstants.MYSQL, "pi()")); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalMethodReverseTest.java b/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalMethodReverseTest.java new file mode 100644 index 0000000000..becb82adf1 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalMethodReverseTest.java @@ -0,0 +1,14 @@ +package com.alibaba.druid.bvt.sql.eval; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import com.alibaba.druid.sql.visitor.SQLEvalVisitorUtils; +import com.alibaba.druid.util.JdbcConstants; + + +public class EvalMethodReverseTest extends TestCase { + public void test_reverse() throws Exception { + Assert.assertEquals("cba", SQLEvalVisitorUtils.evalExpr(JdbcConstants.MYSQL, "REVERSE('abc')")); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalMethodRightTest.java b/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalMethodRightTest.java new file mode 100644 index 0000000000..fe3df33dcb --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalMethodRightTest.java @@ -0,0 +1,14 @@ +package com.alibaba.druid.bvt.sql.eval; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import com.alibaba.druid.sql.visitor.SQLEvalVisitorUtils; +import com.alibaba.druid.util.JdbcConstants; + + +public class EvalMethodRightTest extends TestCase { + public void test_ascii() throws Exception { + Assert.assertEquals("rbar", SQLEvalVisitorUtils.evalExpr(JdbcConstants.MYSQL, "right('foobarbar', 4)")); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalMethodTrimTest.java b/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalMethodTrimTest.java new file mode 100644 index 0000000000..90827af256 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalMethodTrimTest.java @@ -0,0 +1,14 @@ +package com.alibaba.druid.bvt.sql.eval; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import com.alibaba.druid.sql.visitor.SQLEvalVisitorUtils; +import com.alibaba.druid.util.JdbcConstants; + + +public class EvalMethodTrimTest extends TestCase { + public void test_trim() throws Exception { + Assert.assertEquals("bar", SQLEvalVisitorUtils.evalExpr(JdbcConstants.MYSQL, "TRIM(' bar ')")); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalRlikeTest.java b/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalRlikeTest.java new file mode 100644 index 0000000000..e271f389b4 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalRlikeTest.java @@ -0,0 +1,22 @@ +package com.alibaba.druid.bvt.sql.eval; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import com.alibaba.druid.sql.visitor.SQLEvalVisitorUtils; +import com.alibaba.druid.util.JdbcConstants; + + +public class EvalRlikeTest extends TestCase { + public void test_rlike() throws Exception { + Assert.assertEquals(true, SQLEvalVisitorUtils.evalExpr(JdbcConstants.MYSQL, "'a' REGEXP '^[a-d]'")); + Assert.assertEquals(true, SQLEvalVisitorUtils.evalExpr(JdbcConstants.MYSQL, "'a' RLIKE '^[a-d]'")); + Assert.assertEquals(false, SQLEvalVisitorUtils.evalExpr(JdbcConstants.MYSQL, "'1' RLIKE '^[a-d]'")); + } + + public void test_not_rlike() throws Exception { + Assert.assertEquals(false, SQLEvalVisitorUtils.evalExpr(JdbcConstants.MYSQL, "'a' NOT REGEXP '^[a-d]'")); + Assert.assertEquals(false, SQLEvalVisitorUtils.evalExpr(JdbcConstants.MYSQL, "'a' NOT RLIKE '^[a-d]'")); + Assert.assertEquals(true, SQLEvalVisitorUtils.evalExpr(JdbcConstants.MYSQL, "'1' NOT RLIKE '^[a-d]'")); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalSelectTest.java b/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalSelectTest.java new file mode 100644 index 0000000000..39dea061ef --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/eval/EvalSelectTest.java @@ -0,0 +1,21 @@ +package com.alibaba.druid.bvt.sql.eval; + +import java.util.ArrayList; +import java.util.List; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import com.alibaba.druid.sql.visitor.SQLEvalVisitorUtils; +import com.alibaba.druid.util.JdbcConstants; + + +public class EvalSelectTest extends TestCase { + public void test_select() throws Exception { + List> rows = new ArrayList>(); + List row = new ArrayList(); + row.add(1); + rows.add(row); + Assert.assertEquals(rows, SQLEvalVisitorUtils.evalExpr(JdbcConstants.MYSQL, "SELECT 1")); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlInsertTest_0.java b/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlInsertTest_0.java new file mode 100644 index 0000000000..d9e84e2171 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlInsertTest_0.java @@ -0,0 +1,73 @@ +/* + * 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.mysql; + +import java.util.List; + +import junit.framework.Assert; + +import com.alibaba.druid.sql.MysqlTest; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.ast.expr.SQLCharExpr; +import com.alibaba.druid.sql.ast.statement.SQLInsertStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlInsertStatement; +import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser; +import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlSchemaStatVisitor; +import com.alibaba.druid.sql.parser.SQLStatementParser; + +public class MySqlInsertTest_0 extends MysqlTest { + + public void test_0() throws Exception { + String sql = "INSERT INTO t1 (name) VALUES (" + // + "'eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + // + "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + // + "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + // + "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + // + "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + // + "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + // + "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + // + "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + // + "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + // + "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + // + "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + // + "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + // + "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + // + "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + // + "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + // + "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee" + // + "eeeeeeeeeeeeeeeeee\\\\1')"; + + MySqlStatementParser parser = new MySqlStatementParser(sql); + List statementList = parser.parseStatementList(); + SQLStatement stmt = statementList.get(0); + + SQLInsertStatement insertStmt = (SQLInsertStatement) stmt; + + SQLCharExpr charExpr = (SQLCharExpr) insertStmt.getValues().getValues().get(0); + String text = charExpr.getText(); + Assert.assertEquals('1', text.charAt(charExpr.getText().length() - 1)); + Assert.assertEquals('\\', text.charAt(charExpr.getText().length() - 2)); + + print(statementList); + + Assert.assertEquals(1, statementList.size()); + + MySqlSchemaStatVisitor visitor = new MySqlSchemaStatVisitor(); + stmt.accept(visitor); + + // Assert.assertTrue(visitor.getTables().containsKey(new TableStat.Name("mytable"))); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlSelectTest_crossjoin.java b/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlSelectTest_crossjoin.java new file mode 100644 index 0000000000..7ee998ae7d --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/mysql/MySqlSelectTest_crossjoin.java @@ -0,0 +1,65 @@ +/* + * 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.mysql; + +import java.util.List; + +import junit.framework.Assert; + +import com.alibaba.druid.sql.MysqlTest; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.ast.statement.SQLSelect; +import com.alibaba.druid.sql.ast.statement.SQLSelectStatement; +import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock; +import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser; +import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlSchemaStatVisitor; + +public class MySqlSelectTest_crossjoin extends MysqlTest { + + public void test_0() throws Exception { + String sql = "select resource0_.resource_id as resource1_13_, resource0_.asMenu as asMenu13_, resource0_.resource_description as resource3_13_, resource0_.menu_name as menu4_13_, resource0_.resource_name as resource5_13_, resource0_.rg_id as rg7_13_, resource0_.rt_id as rt8_13_, resource0_.resource_serial as resource6_13_ from hnisitc.hnisitc_resource resource0_ cross join hnisitc.hnisitc_resource_type resourcety1_ where resource0_.rt_id=resourcety1_.rt_id and resourcety1_.rt_name='METHOD'"; + + MySqlStatementParser parser = new MySqlStatementParser(sql); + List statementList = parser.parseStatementList(); + SQLStatement stmt = statementList.get(0); + + SQLSelectStatement selectStmt = (SQLSelectStatement) stmt; + + SQLSelect select = selectStmt.getSelect(); + Assert.assertNotNull(select.getQuery()); + MySqlSelectQueryBlock queryBlock = (MySqlSelectQueryBlock) select.getQuery(); + Assert.assertNull(queryBlock.getOrderBy()); + + print(statementList); + + Assert.assertEquals(1, statementList.size()); + + MySqlSchemaStatVisitor visitor = new MySqlSchemaStatVisitor(); + stmt.accept(visitor); + + System.out.println("Tables : " + visitor.getTables()); + System.out.println("fields : " + visitor.getColumns()); + System.out.println("coditions : " + visitor.getConditions()); + System.out.println("orderBy : " + visitor.getOrderByColumns()); + + Assert.assertEquals(2, visitor.getTables().size()); + Assert.assertEquals(10, visitor.getColumns().size()); + Assert.assertEquals(3, visitor.getConditions().size()); + Assert.assertEquals(0, visitor.getOrderByColumns().size()); + +// Assert.assertTrue(visitor.getTables().containsKey(new TableStat.Name("mytable"))); + } +} diff --git a/src/test/java/com/alibaba/druid/bvt/sql/oracle/OracleSelectTest39.java b/src/test/java/com/alibaba/druid/bvt/sql/oracle/OracleSelectTest39.java new file mode 100644 index 0000000000..bcc78ec319 --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/sql/oracle/OracleSelectTest39.java @@ -0,0 +1,66 @@ +/* + * 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.oracle; + +import java.util.List; + +import junit.framework.Assert; + +import com.alibaba.druid.sql.OracleTest; +import com.alibaba.druid.sql.SQLUtils; +import com.alibaba.druid.sql.ast.SQLStatement; +import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr; +import com.alibaba.druid.sql.ast.expr.SQLBinaryOperator; +import com.alibaba.druid.sql.ast.statement.SQLSelect; +import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock; +import com.alibaba.druid.sql.ast.statement.SQLSelectStatement; +import com.alibaba.druid.sql.dialect.oracle.parser.OracleStatementParser; +import com.alibaba.druid.sql.dialect.oracle.visitor.OracleSchemaStatVisitor; +import com.alibaba.druid.stat.TableStat; + +public class OracleSelectTest39 extends OracleTest { + + public void test_0() throws Exception { + String sql = // + "select * from ge_rms_company start with comCode ='11' connect by nocycle prior comCode=UPPERCOMCODE"; // + + OracleStatementParser parser = new OracleStatementParser(sql); + List statementList = parser.parseStatementList(); + SQLStatement statemen = statementList.get(0); + print(statementList); + + Assert.assertEquals(1, statementList.size()); + + OracleSchemaStatVisitor visitor = new OracleSchemaStatVisitor(); + statemen.accept(visitor); + + System.out.println("Tables : " + visitor.getTables()); + System.out.println("fields : " + visitor.getColumns()); + System.out.println("coditions : " + visitor.getConditions()); + System.out.println("relationships : " + visitor.getRelationships()); + System.out.println("orderBy : " + visitor.getOrderByColumns()); + + Assert.assertEquals(1, visitor.getTables().size()); + + Assert.assertTrue(visitor.getTables().containsKey(new TableStat.Name("ge_rms_company"))); + + Assert.assertEquals(3, visitor.getColumns().size()); + +// Assert.assertTrue(visitor.getColumns().contains(new TableStat.Column("acduser.vw_acd_info", "xzqh"))); + + // Assert.assertTrue(visitor.getOrderByColumns().contains(new TableStat.Column("employees", "last_name"))); + } +}