package com.taobao.tddl.optimizer.parse.cobar.visitor;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.reflect.MethodUtils;
import com.alibaba.cobar.parser.ast.expression.BinaryOperatorExpression;
import com.alibaba.cobar.parser.ast.expression.Expression;
import com.alibaba.cobar.parser.ast.expression.PolyadicOperatorExpression;
import com.alibaba.cobar.parser.ast.expression.UnaryOperatorExpression;
import com.alibaba.cobar.parser.ast.expression.arithmeic.ArithmeticAddExpression;
import com.alibaba.cobar.parser.ast.expression.arithmeic.ArithmeticDivideExpression;
import com.alibaba.cobar.parser.ast.expression.arithmeic.ArithmeticIntegerDivideExpression;
import com.alibaba.cobar.parser.ast.expression.arithmeic.ArithmeticModExpression;
import com.alibaba.cobar.parser.ast.expression.arithmeic.ArithmeticMultiplyExpression;
import com.alibaba.cobar.parser.ast.expression.arithmeic.ArithmeticSubtractExpression;
import com.alibaba.cobar.parser.ast.expression.arithmeic.MinusExpression;
import com.alibaba.cobar.parser.ast.expression.bit.BitAndExpression;
import com.alibaba.cobar.parser.ast.expression.bit.BitInvertExpression;
import com.alibaba.cobar.parser.ast.expression.bit.BitOrExpression;
import com.alibaba.cobar.parser.ast.expression.bit.BitShiftExpression;
import com.alibaba.cobar.parser.ast.expression.bit.BitXORExpression;
import com.alibaba.cobar.parser.ast.expression.comparison.BetweenAndExpression;
import com.alibaba.cobar.parser.ast.expression.comparison.ComparisionEqualsExpression;
import com.alibaba.cobar.parser.ast.expression.comparison.ComparisionGreaterThanExpression;
import com.alibaba.cobar.parser.ast.expression.comparison.ComparisionGreaterThanOrEqualsExpression;
import com.alibaba.cobar.parser.ast.expression.comparison.ComparisionIsExpression;
import com.alibaba.cobar.parser.ast.expression.comparison.ComparisionLessOrGreaterThanExpression;
import com.alibaba.cobar.parser.ast.expression.comparison.ComparisionLessThanExpression;
import com.alibaba.cobar.parser.ast.expression.comparison.ComparisionLessThanOrEqualsExpression;
import com.alibaba.cobar.parser.ast.expression.comparison.ComparisionNotEqualsExpression;
import com.alibaba.cobar.parser.ast.expression.comparison.ComparisionNullSafeEqualsExpression;
import com.alibaba.cobar.parser.ast.expression.comparison.InExpression;
import com.alibaba.cobar.parser.ast.expression.logical.LogicalAndExpression;
import com.alibaba.cobar.parser.ast.expression.logical.LogicalNotExpression;
import com.alibaba.cobar.parser.ast.expression.logical.LogicalOrExpression;
import com.alibaba.cobar.parser.ast.expression.logical.LogicalXORExpression;
import com.alibaba.cobar.parser.ast.expression.logical.NegativeValueExpression;
import com.alibaba.cobar.parser.ast.expression.misc.AssignmentExpression;
import com.alibaba.cobar.parser.ast.expression.misc.InExpressionList;
import com.alibaba.cobar.parser.ast.expression.misc.QueryExpression;
import com.alibaba.cobar.parser.ast.expression.misc.SubqueryAllExpression;
import com.alibaba.cobar.parser.ast.expression.misc.SubqueryAnyExpression;
import com.alibaba.cobar.parser.ast.expression.primary.CaseWhenOperatorExpression;
import com.alibaba.cobar.parser.ast.expression.primary.ExistsPrimary;
import com.alibaba.cobar.parser.ast.expression.primary.Identifier;
import com.alibaba.cobar.parser.ast.expression.primary.MatchExpression;
import com.alibaba.cobar.parser.ast.expression.primary.ParamMarker;
import com.alibaba.cobar.parser.ast.expression.primary.RowExpression;
import com.alibaba.cobar.parser.ast.expression.primary.function.FunctionExpression;
import com.alibaba.cobar.parser.ast.expression.primary.function.groupby.Avg;
import com.alibaba.cobar.parser.ast.expression.primary.function.groupby.Count;
import com.alibaba.cobar.parser.ast.expression.primary.function.groupby.Max;
import com.alibaba.cobar.parser.ast.expression.primary.function.groupby.Min;
import com.alibaba.cobar.parser.ast.expression.primary.function.groupby.Sum;
import com.alibaba.cobar.parser.ast.expression.primary.literal.IntervalPrimary;
import com.alibaba.cobar.parser.ast.expression.primary.literal.LiteralBitField;
import com.alibaba.cobar.parser.ast.expression.primary.literal.LiteralBoolean;
import com.alibaba.cobar.parser.ast.expression.primary.literal.LiteralHexadecimal;
import com.alibaba.cobar.parser.ast.expression.primary.literal.LiteralNull;
import com.alibaba.cobar.parser.ast.expression.primary.literal.LiteralNumber;
import com.alibaba.cobar.parser.ast.expression.primary.literal.LiteralString;
import com.alibaba.cobar.parser.ast.expression.string.LikeExpression;
import com.alibaba.cobar.parser.ast.expression.type.CastBinaryExpression;
import com.alibaba.cobar.parser.ast.fragment.tableref.Dual;
import com.alibaba.cobar.parser.ast.fragment.tableref.IndexHint;
import com.alibaba.cobar.parser.ast.fragment.tableref.InnerJoin;
import com.alibaba.cobar.parser.ast.fragment.tableref.NaturalJoin;
import com.alibaba.cobar.parser.ast.fragment.tableref.OuterJoin;
import com.alibaba.cobar.parser.ast.fragment.tableref.StraightJoin;
import com.alibaba.cobar.parser.ast.fragment.tableref.SubqueryFactor;
import com.alibaba.cobar.parser.ast.fragment.tableref.TableRefFactor;
import com.alibaba.cobar.parser.ast.fragment.tableref.TableReference;
import com.alibaba.cobar.parser.ast.stmt.dml.DMLSelectStatement;
import com.alibaba.cobar.parser.recognizer.mysql.lexer.MySQLLexer;
import com.alibaba.cobar.parser.recognizer.mysql.syntax.MySQLExprParser;
import com.alibaba.cobar.parser.visitor.EmptySQLASTVisitor;
import com.alibaba.cobar.parser.visitor.MySQLOutputASTVisitor;
import com.google.common.collect.Maps;
import com.taobao.tddl.common.exception.NotSupportException;
import com.taobao.tddl.optimizer.core.ASTNodeFactory;
import com.taobao.tddl.optimizer.core.ast.QueryTreeNode;
import com.taobao.tddl.optimizer.core.ast.query.JoinNode;
import com.taobao.tddl.optimizer.core.ast.query.TableNode;
import com.taobao.tddl.optimizer.core.expression.IBindVal;
import com.taobao.tddl.optimizer.core.expression.IBooleanFilter;
import com.taobao.tddl.optimizer.core.expression.IColumn;
import com.taobao.tddl.optimizer.core.expression.IFilter;
import com.taobao.tddl.optimizer.core.expression.IFilter.OPERATION;
import com.taobao.tddl.optimizer.core.expression.IFunction;
import com.taobao.tddl.optimizer.core.expression.ILogicalFilter;
import com.taobao.tddl.optimizer.core.expression.ISelectable;
import com.taobao.tddl.optimizer.core.expression.bean.LobVal;
import com.taobao.tddl.optimizer.core.expression.bean.NullValue;
import com.taobao.tddl.optimizer.exceptions.OptimizerException;
/**
* 解析mysql表达式
*
* <pre>
* 参考资料:
* 1. https://dev.mysql.com/doc/refman/5.6/en/comparison-operators.html
* </pre>
*
* @since 5.0.0
*/
public class MySqlExprVisitor extends EmptySQLASTVisitor {
private static Map emptyMap = Maps.newHashMap();
private Comparable columnOrValue;
private QueryTreeNode tableNode = null;
private String valueForLike;
private IFilter filter;
@Override
public void visit(BetweenAndExpression node) {
Expression first = node.getFirst();
Expression second = node.getSecond();
Expression third = node.getThird();
MySqlExprVisitor v = new MySqlExprVisitor();
first.accept(v);
Comparable col = v.getColumnOrValue();
MySqlExprVisitor lv = new MySqlExprVisitor();
second.accept(lv);
Comparable lval = lv.getColumnOrValue();
MySqlExprVisitor rv = new MySqlExprVisitor();
third.accept(rv);
Comparable rval = rv.getColumnOrValue();
IBooleanFilter left = this.buildBooleanFilter(col, lval, OPERATION.GT_EQ, node);
IBooleanFilter right = this.buildBooleanFilter(col, rval, OPERATION.LT_EQ, node);
ILogicalFilter ilf = buildLogicalFilter(left, right, OPERATION.AND, node);
if (node.isNot()) {
ilf.setIsNot(true);
}
this.filter = ilf;
}
@Override
public void visit(ComparisionIsExpression node) {
IBooleanFilter ibf = ASTNodeFactory.getInstance().createBooleanFilter();
MySqlExprVisitor leftEvi = new MySqlExprVisitor();
node.getOperand().accept(leftEvi);
ibf.setColumn(leftEvi.getColumnOrValue());
if (node.getMode() == ComparisionIsExpression.IS_NULL) {
ibf.setOperation(OPERATION.IS_NULL);
// ibf.setValue(NullValue.getNullValue());
ibf.setIsNot(false);
} else if (node.getMode() == ComparisionIsExpression.IS_NOT_NULL) {
ibf.setOperation(OPERATION.IS_NOT_NULL);
// ibf.setValue(NullValue.getNullValue());
// ibf.setIsNot(true);
ibf.setIsNot(false);
} else if (node.getMode() == ComparisionIsExpression.IS_FALSE) {
ibf.setOperation(OPERATION.IS_FALSE);
// ibf.setValue(false);
ibf.setIsNot(false);
} else if (node.getMode() == ComparisionIsExpression.IS_NOT_FALSE) {
ibf.setOperation(OPERATION.IS_NOT_FALSE);
// ibf.setValue(new Boolean(false));
// ibf.setIsNot(true);
ibf.setIsNot(false);
} else if (node.getMode() == ComparisionIsExpression.IS_TRUE) {
ibf.setOperation(OPERATION.IS_TRUE);
// ibf.setValue(new Boolean(true));
ibf.setIsNot(false);
} else if (node.getMode() == ComparisionIsExpression.IS_NOT_TRUE) {
ibf.setOperation(OPERATION.IS_NOT_TRUE);
// ibf.setValue(new Boolean(true));
// ibf.setIsNot(true);
ibf.setIsNot(false);
} else if (node.getMode() == ComparisionIsExpression.IS_UNKNOWN) {
throw new NotSupportException("not support IS_UNKNOWN");
} else if (node.getMode() == ComparisionIsExpression.IS_NOT_UNKNOWN) {
throw new NotSupportException("not support IS_NOT_UNKNOWN");
}
this.filter = ibf;
}
@Override
public void visit(BinaryOperatorExpression node) {
if (eval(node)) { // 计算出了结果
return;
}
if (node instanceof ComparisionEqualsExpression) {
this.handleBooleanFilter(node, OPERATION.EQ);
} else if (node instanceof ComparisionGreaterThanExpression) {
this.handleBooleanFilter(node, OPERATION.GT);
} else if (node instanceof ComparisionGreaterThanOrEqualsExpression) {
this.handleBooleanFilter(node, OPERATION.GT_EQ);
} else if (node instanceof ComparisionLessOrGreaterThanExpression) {
this.handleBooleanFilter(node, OPERATION.NOT_EQ);
} else if (node instanceof ComparisionLessThanExpression) {
this.handleBooleanFilter(node, OPERATION.LT);
} else if (node instanceof ComparisionLessThanOrEqualsExpression) {
this.handleBooleanFilter(node, OPERATION.LT_EQ);
} else if (node instanceof ComparisionNotEqualsExpression) {
this.handleBooleanFilter(node, OPERATION.NOT_EQ);
} else if (node instanceof ComparisionNullSafeEqualsExpression) {
throw new NotSupportException("not support '<=>' ");
} else if (node instanceof ArithmeticAddExpression) {
this.handleArithmetric(node, IFunction.BuiltInFunction.ADD);
} else if (node instanceof ArithmeticDivideExpression) {
this.handleArithmetric(node, IFunction.BuiltInFunction.DIVISION);
} else if (node instanceof ArithmeticIntegerDivideExpression) {
this.handleArithmetric(node, node.getOperator());
} else if (node instanceof ArithmeticModExpression) {
this.handleArithmetric(node, IFunction.BuiltInFunction.MOD);
} else if (node instanceof ArithmeticMultiplyExpression) {
this.handleArithmetric(node, IFunction.BuiltInFunction.MULTIPLY);
} else if (node instanceof ArithmeticSubtractExpression) {
this.handleArithmetric(node, IFunction.BuiltInFunction.SUB);
} else if (node instanceof AssignmentExpression) {
throw new NotSupportException("not support ':=' ");
} else if (node instanceof BitAndExpression) {
this.handleArithmetric(node, IFunction.BuiltInFunction.BITAND);
} else if (node instanceof BitOrExpression) {
this.handleArithmetric(node, IFunction.BuiltInFunction.BITOR);
} else if (node instanceof BitShiftExpression) {
if (((BitShiftExpression) node).isRightShift()) {
this.handleArithmetric(node, IFunction.BuiltInFunction.BITRSHIFT);
} else {
this.handleArithmetric(node, IFunction.BuiltInFunction.BITLSHIFT);
}
} else if (node instanceof BitXORExpression) {
this.handleArithmetric(node, IFunction.BuiltInFunction.BITXOR);
} else if (node instanceof InExpression) {
this.handleInExpression((InExpression) node);
} else if (node instanceof LogicalXORExpression) {
this.handleBooleanFilter(node, OPERATION.XOR);
} else {
throw new NotSupportException("not supported this BinaryOperatorExpression type " + node.getOperator());
}
}
@Override
public void visit(UnaryOperatorExpression node) {
if (eval(node)) { // 计算出了结果
return;
}
if (node instanceof BitInvertExpression) {
} else if (node instanceof CastBinaryExpression) {
} else if (node instanceof LogicalNotExpression) {
} else if (node instanceof MinusExpression) {
} else if (node instanceof NegativeValueExpression) {
throw new NotSupportException("not support NegativeValueExpression");
} else if (node instanceof SubqueryAllExpression) {
throw new NotSupportException("not support SubqueryAllExpression");
} else if (node instanceof SubqueryAnyExpression) {
throw new NotSupportException("not support SubqueryAnyExpression");
} else {
throw new NotSupportException("not supported this UnaryOperatorExpression type " + node.getOperator());
}
IFunction f = ASTNodeFactory.getInstance().createFunction();
if (node instanceof MinusExpression) {
f.setFunctionName(IFunction.BuiltInFunction.MINUS);
} else {
f.setFunctionName(node.getOperator());
}
MySqlExprVisitor ev = new MySqlExprVisitor();
node.getOperand().accept(ev);
Object arg = ev.getColumnOrValue();
List args = new ArrayList(1);
args.add(arg);
f.setArgs(args);
f.setColumnName(this.getSqlExprStr(node));
columnOrValue = f;
}
@Override
public void visit(FunctionExpression node) {
boolean argDistinct = isDistinct(node);
IFunction ifunc = ASTNodeFactory.getInstance().createFunction();
ifunc.setFunctionName(node.getFunctionName());
List<Expression> expressions = node.getArguments();
if (expressions != null) {
ArrayList<Object> args = new ArrayList<Object>();
for (Expression expr : expressions) {
MySqlExprVisitor v = new MySqlExprVisitor();
expr.accept(v);
Object cv = v.getColumnOrValue();
if ((cv instanceof ISelectable)) {
((ISelectable) cv).setDistinct(argDistinct);
}
args.add(v.getColumnOrValue());
}
ifunc.setArgs(args);
} else {
ifunc.setArgs(new ArrayList());
}
ifunc.setColumnName(getSqlExprStr(node));
columnOrValue = ifunc;
}
@Override
public void visit(RowExpression node) {
IFunction ifunc = ASTNodeFactory.getInstance().createFunction();
ifunc.setFunctionName(IFunction.BuiltInFunction.ROW);
List<Comparable> args = new ArrayList<Comparable>();
for (int i = 0; i < node.getRowExprList().size(); i++) {
MySqlExprVisitor mv = new MySqlExprVisitor();
node.getRowExprList().get(i).accept(mv);
Object obj = mv.getColumnOrValue();
args.add((Comparable) obj);
}
ifunc.setArgs(args);
ifunc.setColumnName(getSqlExprStr(node));
columnOrValue = ifunc;
}
@Override
public void visit(Identifier node) {
IColumn column = ASTNodeFactory.getInstance().createColumn();
if (node.getParent() != null) { // table.column
column.setTableName(node.getParent().getIdTextUpUnescape());
}
column.setColumnName(node.getIdTextUpUnescape());
this.columnOrValue = column;
}
@Override
public void visit(InnerJoin node) { // inner join
TableReference ltable = node.getLeftTableRef();
TableReference rtable = node.getRightTableRef();
JoinNode joinNode = commonJoin(ltable, rtable);
Expression cond = node.getOnCond();
if (cond != null) {
MySqlExprVisitor ev = new MySqlExprVisitor();
cond.accept(ev);
IFilter ifilter = ev.getFilter();
joinNode.setInnerJoin();
addJoinOnColumns(ifilter, joinNode);
} else if (node.getUsing() != null && node.getUsing().size() != 0) {
IFilter ifilter = this.getUsingFilter(node.getUsing());
joinNode.setInnerJoin();
addJoinOnColumns(ifilter, joinNode);
}
this.tableNode = joinNode;
}
@Override
public void visit(NaturalJoin node) { // 默认是同名字段完全匹配的 INNER JOIN
TableReference ltable = node.getLeftTableRef();
TableReference rtable = node.getRightTableRef();
JoinNode joinNode = commonJoin(ltable, rtable);
this.tableNode = joinNode;
}
@Override
public void visit(OuterJoin node) {// left/right join
TableReference ltable = node.getLeftTableRef();
TableReference rtable = node.getRightTableRef();
JoinNode joinNode = commonJoin(ltable, rtable);
Expression cond = node.getOnCond();
if (cond != null) {
MySqlExprVisitor ev = new MySqlExprVisitor();
cond.accept(ev);
IFilter ifilter = ev.getFilter();
if (node.isLeftJoin()) {
joinNode.setLeftOuterJoin();
} else {
joinNode.setRightOuterJoin();
}
addJoinOnColumns(ifilter, joinNode);
} else if (node.getUsing() != null && node.getUsing().size() != 0) {
IFilter ifilter = this.getUsingFilter(node.getUsing());
if (node.isLeftJoin()) {
joinNode.setLeftOuterJoin();
} else {
joinNode.setRightOuterJoin();
}
addJoinOnColumns(ifilter, joinNode);
}
this.tableNode = joinNode;
}
@Override
public void visit(StraightJoin node) {// inner join
TableReference ltable = node.getLeftTableRef();
TableReference rtable = node.getRightTableRef();
JoinNode joinNode = commonJoin(ltable, rtable);
Expression cond = node.getOnCond();
if (cond != null) {
MySqlExprVisitor ev = new MySqlExprVisitor();
cond.accept(ev);
IFilter ifilter = ev.getFilter();
joinNode.setInnerJoin();
addJoinOnColumns(ifilter, joinNode);
}
this.tableNode = joinNode;
}
@Override
public void visit(IntervalPrimary node) {
IFunction f = ASTNodeFactory.getInstance().createFunction();
f.setColumnName(this.getSqlExprStr(node));
f.setFunctionName(IFunction.BuiltInFunction.INTERVAL);
Expression quantity = node.getQuantity();
MySqlExprVisitor ev = new MySqlExprVisitor();
quantity.accept(ev);
List args = new ArrayList(2);
args.add(ev.getColumnOrValue());
args.add(node.getUnit().toString());
f.setArgs(args);
this.columnOrValue = f;
}
@Override
public void visit(LikeExpression node) {
MySqlExprVisitor first = new MySqlExprVisitor();
node.getFirst().accept(first);
MySqlExprVisitor second = new MySqlExprVisitor();
node.getSecond().accept(second);
Comparable value = null;
if (second.getValueForLike() != null) {
value = second.getValueForLike();
} else {
value = second.getColumnOrValue();
}
this.filter = this.buildBooleanFilter(first.getColumnOrValue(), value, OPERATION.LIKE, node);
if (node.isNot()) {
this.filter.setIsNot(true);
}
// TODO: 支持下like下的ESCAPE参数
// just like: higherPreExpr 'NOT'? 'LIKE' higherPreExpr ('ESCAPE'
// higherPreExpr)?
}
@Override
public void visit(LiteralBitField node) {
if (node.getIntroducer() != null) {
throw new NotSupportException("bit value not support introducer:" + node.getIntroducer());
}
this.columnOrValue = new LobVal(node.getText(), "b");
}
@Override
public void visit(LiteralBoolean node) {
this.columnOrValue = node.isTrue();
}
@Override
public void visit(LiteralHexadecimal node) {
if (node.getIntroducer() != null) {
throw new NotSupportException("hex value not support introducer:" + node.getIntroducer());
}
this.columnOrValue = new LobVal(node.getText(), "x");
}
@Override
public void visit(LiteralNull node) {
this.columnOrValue = NullValue.getNullValue();
}
@Override
public void visit(LiteralNumber node) {
this.columnOrValue = (Comparable) node.getNumber();
}
@Override
public void visit(LiteralString node) {
if (node.getIntroducer() != null) {
this.columnOrValue = new LobVal(node.getString(), node.getIntroducer());
} else {
// 由于是绑定变量的形式,普通的操作符要用转义后的,但是like的不行,似乎like比较特殊....
this.columnOrValue = node.getUnescapedString();
this.valueForLike = node.getString();
}
}
@Override
public void visit(ParamMarker node) {
IBindVal val = ASTNodeFactory.getInstance().createBindValue(node.getParamIndex());
columnOrValue = val;
}
@Override
public void visit(PolyadicOperatorExpression node) {
if (eval(node)) {// 已经计算出了结果
return;
}
IFilter root = null;
for (int i = 0; i < node.getArity(); i++) {
Expression expr = node.getOperand(i);
MySqlExprVisitor ev = new MySqlExprVisitor();
expr.accept(ev);
if (expr instanceof LiteralBoolean) {
if ((Boolean) ev.getColumnOrValue()) {
ev.filter = this.buildConstanctFilter(1);
} else {
ev.filter = this.buildConstanctFilter(0);
}
}
if (ev.getFilter() == null) {
if (ev.getColumnOrValue() != null) {
// a or b , a封到一个booleanFilter里
ev.filter = this.buildBooleanFilter(ev.getColumnOrValue(), null, OPERATION.CONSTANT, node);
} else {
throw new NotSupportException("and/or不能没有操作符");
}
}
if (root == null) {
root = ev.getFilter();
} else {
if (node instanceof LogicalAndExpression) {
root = this.buildLogicalFilter(root, ev.getFilter(), OPERATION.AND, node);
} else if (node instanceof LogicalOrExpression) {
root = this.buildLogicalFilter(root, ev.getFilter(), OPERATION.OR, node);
} else {
throw new NotSupportException(); // 不会到这一步
}
}
}
this.filter = root;
}
@Override
public void visit(SubqueryFactor node) {
MySqlSelectVisitor v = new MySqlSelectVisitor();
node.accept(v);
tableNode = v.getTableNode();
tableNode.setSubQuery(true);
if (node.getAliasUnescapeUppercase() != null) {
if (tableNode.getAlias() != null) {
tableNode.setSubAlias(tableNode.getAlias());// 内部子查询的别名
}
tableNode.alias(node.getAliasUnescapeUppercase());
}
}
@Override
public void visit(TableRefFactor node) {
TableNode table = new TableNode(node.getTable().getIdTextUpUnescape());
if (node.getAliasUnescapeUppercase() != null) {
table.alias(node.getAliasUnescapeUppercase());
}
this.tableNode = table;
}
@Override
public void visit(CaseWhenOperatorExpression node) {
throw new NotSupportException("CaseWhenOperatorExpression");
}
@Override
public void visit(ExistsPrimary node) {
throw new NotSupportException("ExistsPrimary");
}
@Override
public void visit(MatchExpression node) {
throw new NotSupportException("MatchExpression");
}
@Override
public void visit(IndexHint node) {
throw new NotSupportException("IndexHint");
}
@Override
public void visit(Dual dual) {
throw new NotSupportException("Dual");
}
// ================== helper =====================
public static MySqlExprVisitor parser(String condition) {
if (StringUtils.isEmpty(condition)) {
return null;
}
condition = condition.toUpperCase();
try {
// 调用cobar的expression解析器
MySQLExprParser expr = new MySQLExprParser(new MySQLLexer(condition));
Expression expression = expr.expression();
// 反射调用visit构造IFilter
MySqlExprVisitor parser = new MySqlExprVisitor();
Class args = expression.getClass();
Method method = null;
while (true) {
method = MethodUtils.getAccessibleMethod(parser.getClass(), "visit", args);
if (method == null) {
args = args.getSuperclass();
if (args == null) {
throw new NotSupportException("parse failed : " + condition);
}
} else {
break;
}
}
method.invoke(parser, expression);
return parser;
} catch (Exception e) {
throw new OptimizerException(e);
}
}
public IBooleanFilter buildBooleanFilter(Object column, Object value, OPERATION operation, Expression exp) {
IBooleanFilter ibf = ASTNodeFactory.getInstance().createBooleanFilter();
ibf.setColumn(column);
ibf.setValue(value);
ibf.setOperation(operation);
if (exp != null) {
ibf.setColumnName(getSqlExprStr(exp)); // 比如将count(*)做为columnName
}
return ibf;
}
public ILogicalFilter buildLogicalFilter(IFilter column, IFilter value, OPERATION operation, Expression exp) {
ILogicalFilter ibf = ASTNodeFactory.getInstance().createLogicalFilter();
ibf.addSubFilter(column);
ibf.addSubFilter(value);
ibf.setOperation(operation);
if (exp != null) {
ibf.setColumnName(getSqlExprStr(exp));
}
return ibf;
}
public IBooleanFilter buildConstanctFilter(Comparable constant) {
IBooleanFilter f = ASTNodeFactory.getInstance().createBooleanFilter();
f.setOperation(OPERATION.CONSTANT);
f.setColumn(constant);
f.setColumnName(ObjectUtils.toString(constant));
return f;
}
protected boolean eval(Expression expr) {
Object value = expr.evaluation(emptyMap);
if (value != null && value != Expression.UNEVALUATABLE) {
this.columnOrValue = (Comparable) value;
return true;
}
return false;
}
private void handleBooleanFilter(BinaryOperatorExpression node, OPERATION op) {
MySqlExprVisitor lv = new MySqlExprVisitor();
node.getLeftOprand().accept(lv);
if (node.getRightOprand() instanceof DMLSelectStatement) {
// 处理id = (subquery)
MySqlSelectVisitor rv = new MySqlSelectVisitor();
node.getRightOprand().accept(rv);
this.filter = buildBooleanFilter(lv.getColumnOrValue(), rv.getTableNode(), op, node);
} else {
MySqlExprVisitor rv = new MySqlExprVisitor();
node.getRightOprand().accept(rv);
this.filter = buildBooleanFilter(lv.getColumnOrValue(), rv.getColumnOrValue(), op, node);
}
}
private void handleArithmetric(BinaryOperatorExpression expr, String functionName) {
IFunction func = ASTNodeFactory.getInstance().createFunction();
func.setFunctionName(functionName);
List<Object> args = new ArrayList<Object>(2);
MySqlExprVisitor leftevi = new MySqlExprVisitor();
expr.getLeftOprand().accept(leftevi);
args.add(leftevi.getColumnOrValue());
MySqlExprVisitor rightevi = new MySqlExprVisitor();
expr.getRightOprand().accept(rightevi);
args.add(rightevi.getColumnOrValue());
func.setArgs(args); // 设置参数
func.setColumnName(getSqlExprStr(expr));
this.columnOrValue = func;
}
private void handleInExpression(InExpression node) {
MySqlExprVisitor left = new MySqlExprVisitor();
node.getLeftOprand().accept(left);
Object leftColumn = left.getColumnOrValue();
IBooleanFilter filter = buildBooleanFilter(leftColumn, null, OPERATION.IN, node);
// 构建values参数
Expression ex = node.getRightOprand();
if (ex instanceof InExpressionList) {
List<Expression> elist = ((InExpressionList) ex).getList();
List<Object> values = new ArrayList<Object>();
for (Expression expr : elist) {
MySqlExprVisitor v = new MySqlExprVisitor();
expr.accept(v);
values.add(v.getColumnOrValue());
}
filter.setValues(values);
} else if (ex instanceof QueryExpression) {
MySqlSelectVisitor v = new MySqlSelectVisitor();
ex.accept(v);
filter.setValues(Arrays.asList((Object) v.getTableNode()));
}
this.filter = filter;
if (node.isNot()) {// not in
filter.setIsNot(true);
}
}
/**
* get function arg is distinct
*
* @param node
* @return
*/
private boolean isDistinct(FunctionExpression node) {
if (node instanceof Avg) {
return ((Avg) node).isDistinct();
} else if (node instanceof Max) {
return ((Max) node).isDistinct();
} else if (node instanceof Min) {
return ((Min) node).isDistinct();
} else if (node instanceof Count) {
return ((Count) node).isDistinct();
} else if (node instanceof Sum) {
return ((Sum) node).isDistinct();
// if have other function support distinct,add here
} else {
return false;
}
}
private JoinNode commonJoin(TableReference ltable, TableReference rtable) {
MySqlExprVisitor lv = new MySqlExprVisitor();
ltable.accept(lv);
QueryTreeNode left = lv.getTableNode();
MySqlExprVisitor rv = new MySqlExprVisitor();
rtable.accept(rv);
QueryTreeNode right = rv.getTableNode();
JoinNode joinNode = left.join(right);
return joinNode;
}
private void addJoinOnColumns(IFilter ifilter, JoinNode joinNode) {
if (ifilter instanceof IBooleanFilter) {
joinNode.addJoinFilter((IBooleanFilter) ifilter);
} else if (ifilter instanceof ILogicalFilter) {
ILogicalFilter ilf = (ILogicalFilter) ifilter;
if (!ilf.getOperation().equals(OPERATION.AND)) {
// 比如出现 A.id = B.id And ( A.id = 1 or A.name = 3)
// 这里的or条件可直接做为other join filter
// 如果出现 A.id = B.id OR A.name = B.name,那就是一个未知情况了
joinNode.setOtherJoinOnFilter(ilf);
} else {
List<IFilter> subFilter = ilf.getSubFilter();
if (subFilter != null) {
for (IFilter one : subFilter) {
addJoinOnColumns(one, joinNode);
}
} else {
throw new IllegalStateException("and has no other columns , " + ifilter);
}
}
}
}
private IFilter getUsingFilter(List<String> using) {
IFilter ifilter = null;
if (using.size() == 1) {
IColumn column1 = ASTNodeFactory.getInstance().createColumn();
column1.setColumnName(using.get(0).toUpperCase());
IColumn column2 = ASTNodeFactory.getInstance().createColumn();
column2.setColumnName(using.get(0).toUpperCase());
ifilter = this.buildBooleanFilter(column1, column2, OPERATION.EQ, null);
ifilter.setColumnName(column1.getColumnName() + "=" + column2.getColumnName());
} else {
ILogicalFilter temp = ASTNodeFactory.getInstance().createLogicalFilter();
temp.setOperation(OPERATION.AND);
for (String us : using) {
IColumn column1 = ASTNodeFactory.getInstance().createColumn();
column1.setColumnName(us.toUpperCase());
IColumn column2 = ASTNodeFactory.getInstance().createColumn();
column2.setColumnName(us.toUpperCase());
IFilter subFilter = this.buildBooleanFilter(column1, column2, OPERATION.EQ, null);
subFilter.setColumnName(column1.getColumnName() + "=" + column2.getColumnName());
temp.addSubFilter(subFilter);
}
ifilter = temp;
}
return ifilter;
}
/**
* get the whole expression string,include everything of this node
*/
protected String getSqlExprStr(Expression expr) {
StringBuilder str = new StringBuilder();
MySQLOutputASTVisitor oa = new MySQLOutputASTVisitor(str);
expr.accept(oa);
return str.toString();
}
// ================== getter =====================
public Comparable getColumnOrValue() {
if (columnOrValue == null) {
return filter;
} else {
return columnOrValue;
}
}
public Comparable getValueForLike() {
return valueForLike;
}
public IFilter getFilter() {
return filter;
}
public QueryTreeNode getTableNode() {
return tableNode;
}
}