package com.taobao.tddl.optimizer.core.ast;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import com.taobao.tddl.common.jdbc.ParameterContext;
import com.taobao.tddl.optimizer.core.ASTNodeFactory;
import com.taobao.tddl.optimizer.core.ast.build.QueryTreeNodeBuilder;
import com.taobao.tddl.optimizer.core.ast.query.JoinNode;
import com.taobao.tddl.optimizer.core.ast.query.MergeNode;
import com.taobao.tddl.optimizer.core.ast.query.TableNode;
import com.taobao.tddl.optimizer.core.datatype.DataType;
import com.taobao.tddl.optimizer.core.expression.IBindVal;
import com.taobao.tddl.optimizer.core.expression.IBooleanFilter;
import com.taobao.tddl.optimizer.core.expression.IFilter;
import com.taobao.tddl.optimizer.core.expression.IFilter.OPERATION;
import com.taobao.tddl.optimizer.core.expression.ILogicalFilter;
import com.taobao.tddl.optimizer.core.expression.IOrderBy;
import com.taobao.tddl.optimizer.core.expression.ISelectable;
import com.taobao.tddl.optimizer.core.plan.IQueryTree;
import com.taobao.tddl.optimizer.core.plan.IQueryTree.LOCK_MODEL;
import com.taobao.tddl.optimizer.core.plan.query.IParallelizableQueryTree.QUERY_CONCURRENCY;
import com.taobao.tddl.optimizer.exceptions.QueryException;
import com.taobao.tddl.optimizer.utils.FilterUtils;
import com.taobao.tddl.optimizer.utils.OptimizerUtils;
/**
* 一个抽象的公共查询树实现 可能是一个真正的queryNode,也可以是个join,或者merge实现 这是个核心的公共实现方法。
*
* @author Dreamond
* @author jianghang 2013-11-8 下午2:33:51
* @since 5.0.0
*/
public abstract class QueryTreeNode extends ASTNode<QueryTreeNode> {
public static enum FilterType {
/**
* 如果有索引,就是索引上的keyFilter,如果没索引,就是主表上的KeyFilter
*/
IndexQueryKeyFilter,
/**
* 在主表上的ValueFilter
*/
ResultFilter,
/**
* 在索引表上的ValueFilter
*/
IndexQueryValueFilter;
}
protected IFilter resultFilter;
protected IFilter keyFilter;
/**
* 包含所有子节点的filter,用于拼sql
*/
protected IFilter allWhereFilter = null;
/**
* select查询中的列
*/
protected List<ISelectable> columnsSelected = new ArrayList<ISelectable>();
/**
* 依赖的所有列,可以理解为columnsSelected + implicitSelectable的总合
*/
protected List<ISelectable> columnsRefered = new ArrayList<ISelectable>();
/**
* 显式的由查询接口指定的orderBy,注意需要保证顺序
*/
protected List<IOrderBy> orderBys = new LinkedList<IOrderBy>();
/**
* 显式的由查询接口指定的group by,注意需要保证顺序
*/
protected List<IOrderBy> groups = new LinkedList<IOrderBy>();
/**
* having条件
*/
protected IFilter havingFilter;
/**
* 上一层父节点,比如子查询会依赖父节点的字段信息
* http://dev.mysql.com/doc/refman/5.0/en/correlated-subqueries.html
*/
protected ASTNode parent = null;
/**
* join的子节点
*/
protected List<ASTNode> children = new ArrayList<ASTNode>(2);
/**
* 从哪里开始
*/
protected Comparable limitFrom = null;
/**
* 到哪里结束
*/
protected Comparable limitTo = null;
/**
* filter in where
*/
protected IFilter whereFilter = null;
/**
* 非column=column的join列
*/
protected IFilter otherJoinOnFilter;
/**
* 当前qn的别名,用于进行join等操作的时候辨别到底这一行是从哪个subNode来的。
*/
protected String alias;
/**
* 如果出现subQuery,内外都存在别名时,内部的别名为subAlias,外部使用的别名为alias
*/
protected String subAlias;
protected boolean consistent = true;
protected LOCK_MODEL lockModel = LOCK_MODEL.SHARED_LOCK;
/**
* 当前节点是否为子查询
*/
protected boolean subQuery = false;
protected boolean needBuild = true;
protected QUERY_CONCURRENCY queryConcurrency;
/**
* 是否为存在聚合信息,比如出现limit/group by/count/max等,此节点就会被标记为true,不允许进行join merge
* join的展开优化
*/
protected boolean isExistAggregate = false;
/**
* 获取完整的order by列信息(包括隐藏,比如group by会转化为order by)
*/
public abstract List<IOrderBy> getImplicitOrderBys();
@Override
public abstract IQueryTree toDataNodeExecutor() throws QueryException;
/**
* 获取builder对象
*/
public abstract QueryTreeNodeBuilder getBuilder();
public abstract String getName();
/**
* 需要子类实现各自的转换
*/
public QueryTreeNode convertToJoinIfNeed() {
for (int i = 0; i < this.getChildren().size(); i++) {
if (this.getChildren().get(i) instanceof QueryTreeNode) {
this.getChildren().set(i, ((QueryTreeNode) this.getChildren().get(i)).convertToJoinIfNeed());
}
}
return this;
}
@Override
public void assignment(Map<Integer, ParameterContext> parameterSettings) {
for (ASTNode child : this.getChildren()) {
child.assignment(parameterSettings);
}
this.keyFilter = OptimizerUtils.assignment(this.keyFilter, parameterSettings);
this.whereFilter = OptimizerUtils.assignment(this.whereFilter, parameterSettings);
this.allWhereFilter = OptimizerUtils.assignment(this.allWhereFilter, parameterSettings);
this.havingFilter = OptimizerUtils.assignment(this.havingFilter, parameterSettings);
this.resultFilter = OptimizerUtils.assignment(this.resultFilter, parameterSettings);
this.columnsSelected = OptimizerUtils.assignment(this.columnsSelected, parameterSettings);
this.otherJoinOnFilter = OptimizerUtils.assignment(this.otherJoinOnFilter, parameterSettings);
if (this.limitFrom instanceof IBindVal) {
Object value = ((IBindVal) limitFrom).assignment(parameterSettings);
limitFrom = (Comparable) OptimizerUtils.convertType(value, DataType.LongType);
}
if (this.limitTo instanceof IBindVal) {
Object value = ((IBindVal) limitTo).assignment(parameterSettings);
limitTo = (Comparable) OptimizerUtils.convertType(value, DataType.LongType);
}
}
// =================== build / copy =========================
protected void setNeedBuild(boolean needBuild) {
this.needBuild = needBuild;
}
@Override
public String toString() {
return this.toString(0);
}
// ======================= setter / getter ======================
public Comparable getLimitFrom() {
return limitFrom;
}
public QueryTreeNode setLimitFrom(Comparable limitFrom) {
if (limitFrom != null && !(limitFrom instanceof IBindVal)) {
this.limitFrom = Long.valueOf(limitFrom.toString());
}
this.limitFrom = limitFrom;
return this;
}
public Comparable getLimitTo() {
return limitTo;
}
public QueryTreeNode setLimitTo(Comparable limitTo) {
if (limitTo != null && !(limitTo instanceof IBindVal)) {
this.limitTo = Long.valueOf(limitTo.toString());
}
this.limitTo = limitTo;
return this;
}
public QueryTreeNode limit(long i, long j) {
this.setLimitFrom(i);
this.setLimitTo(j);
return this;
}
public IFilter getWhereFilter() {
return whereFilter;
}
public QueryTreeNode query(IFilter whereFilter) {
this.whereFilter = whereFilter;
setNeedBuild(true);
return this;
}
public QueryTreeNode query(String where) {
this.whereFilter = FilterUtils.createFilter(where);
return this;
}
public String getAlias() {
return alias;
}
public QueryTreeNode alias(String alias) {
this.alias = alias;
setNeedBuild(true);
return this;
}
public QueryTreeNode subAlias(String alias) {
this.subAlias = alias;
setNeedBuild(true);
return this;
}
public List<IOrderBy> getGroupBys() {
return this.groups;
}
public QueryTreeNode setGroupBys(List<IOrderBy> groups) {
this.groups = groups;
setNeedBuild(true);
return this;
}
public List<IOrderBy> getOrderBys() {
return orderBys;
}
public void setOrderBys(List<IOrderBy> orderBys) {
this.orderBys = orderBys;
setNeedBuild(true);
}
public IFilter getResultFilter() {
return this.resultFilter;
}
public void setResultFilter(IFilter f) {
this.resultFilter = f;
setNeedBuild(true);
}
public void addResultFilter(IBooleanFilter filter) {
if (this.resultFilter == null) {
this.resultFilter = filter;
return;
}
if (this.resultFilter instanceof ILogicalFilter) {
// 添加为子节点
((ILogicalFilter) resultFilter).addSubFilter(filter);
setNeedBuild(true);
} else {
// 将自己做为一个Logical filter的子条件
IFilter sub = this.resultFilter;
resultFilter = ASTNodeFactory.getInstance().createLogicalFilter();
resultFilter.setOperation(OPERATION.AND);
((ILogicalFilter) resultFilter).addSubFilter(sub);
}
}
public IFilter getKeyFilter() {
return this.keyFilter;
}
public void setKeyFilter(IFilter f) {
this.keyFilter = f;
setNeedBuild(true);
}
public List<ASTNode> getChildren() {
return this.children;
}
public ASTNode getChild() {
if (this.getChildren().isEmpty()) {
return null;
}
return this.getChildren().get(0);
}
public void addChild(ASTNode childNode) {
this.children.add(childNode);
}
public QueryTreeNode parent(QueryTreeNode qtn) {
this.parent = qtn;
return this;
}
public List<ISelectable> getColumnsSelected() {
return columnsSelected;
}
public QueryTreeNode setColumnsSelected(List<ISelectable> columnsSelected) {
this.columnsSelected = columnsSelected;
return this;
}
/**
* 添加一个不存在的字段
*/
public void addColumnsSelected(ISelectable selected) {
if (!columnsSelected.contains(selected)) {
columnsSelected.add(selected);
}
}
/**
* 添加一个不存在的字段
*/
public void addColumnsRefered(ISelectable selected) {
if (!columnsRefered.contains(selected)) {
columnsRefered.add(selected);
}
}
/**
* 判断一个字段是否存在于当前库
*/
public boolean hasColumn(ISelectable c) {
return this.getBuilder().findColumn(c) != null;
}
/**
* 根据字段获取一下字段,查询的字段可能来自于select或者from
*/
public ISelectable findColumn(ISelectable c) {
return this.getBuilder().findColumn(c);
}
public QueryTreeNode select(List<ISelectable> columnSelected) {
this.columnsSelected = columnSelected;
setNeedBuild(true);
return this;
}
public QueryTreeNode select(ISelectable... columnSelected) {
this.select(new ArrayList<ISelectable>(Arrays.asList(columnSelected)));
return this;
}
public List<ISelectable> getColumnsRefered() {
return this.columnsRefered;
}
public void setColumnsRefered(List<ISelectable> columnsRefered) {
this.columnsRefered = columnsRefered;
}
/**
* 列的tablename会设为表别名
*
* @return
*/
public List<ISelectable> getColumnsSelectedForParent() {
List<ISelectable> res = new ArrayList<ISelectable>(this.getColumnsSelected().size());
for (ISelectable s : this.getColumnsSelected()) {
ISelectable a = s.copy();
if (this.getAlias() != null) {
a.setTableName(this.getAlias());
}
if (s.getAlias() != null) {
a.setColumnName(s.getAlias()); // 设置为alias name
a.setAlias(null);
}
res.add(a);
}
return res;
}
/**
* 列的tablename会设为表别名
*
* @return
*/
public List<ISelectable> getColumnsReferedForParent() {
if (this.getAlias() == null) {
return this.getColumnsRefered();
} else {
List<ISelectable> res = new ArrayList<ISelectable>(this.getColumnsRefered().size());
for (ISelectable s : this.getColumnsRefered()) {
ISelectable a = s.copy();
if (this.getAlias() != null) {
a.setTableName(this.getAlias());
}
if (s.getAlias() != null) {
a.setColumnName(s.getAlias()); // 设置为alias name
a.setAlias(null);
}
res.add(a);
}
return res;
}
}
/**
* 列的tablename会设为表别名
*
* @return
*/
public boolean containsColumnsReferedForParent(ISelectable c) {
if (c instanceof IBooleanFilter) {
if (((IBooleanFilter) c).getOperation().equals(OPERATION.CONSTANT)) {
return true;
}
}
return this.getColumnsReferedForParent().contains(c);
}
/**
* join 其他节点
*
* @param o
* @return
*/
public JoinNode join(QueryTreeNode o) {
JoinNode joinNode = new JoinNode();
joinNode.addChild(this);
joinNode.addChild(o);
return joinNode;
}
public JoinNode join(String rightNode) {
return this.join(new TableNode(rightNode));
}
public JoinNode join(String rightTable, String rightFilter, String leftKey, String rightKey) {
return this.join(new TableNode(rightTable).query(rightFilter)).addJoinKeys(leftKey, rightKey);
}
public JoinNode join(String rightTable, String rightFilter) {
return this.join(new TableNode(rightTable).query(rightFilter));
}
public JoinNode join(String rightTable, String leftKey, String rightKey) {
return this.join(new TableNode(rightTable)).addJoinKeys(leftKey, rightKey);
}
public JoinNode join(QueryTreeNode rightNode, String leftKey, String rightKey) {
return this.join(rightNode).addJoinKeys(leftKey, rightKey);
}
public MergeNode merge(ASTNode o) {
MergeNode m = new MergeNode();
m.addChild(this);
m.addChild(o);
return m;
}
public MergeNode merge(List<ASTNode> os) {
MergeNode m = new MergeNode();
m.addChild(this);
m.getChildren().addAll(os);
return m;
}
public QueryTreeNode groupBy(ISelectable c, boolean b) {
IOrderBy orderBy = ASTNodeFactory.getInstance().createOrderBy();
orderBy.setColumn(c);
orderBy.setDirection(b);
this.groups.add(orderBy);
setNeedBuild(true);
return this;
}
public QueryTreeNode groupBy(ISelectable c) {
IOrderBy orderBy = ASTNodeFactory.getInstance().createOrderBy();
orderBy.setColumn(c);
setNeedBuild(true);
this.groups.add(orderBy);
return this;
}
public QueryTreeNode groupBy(String group) {
return this.groupBy(OptimizerUtils.createColumnFromString(group));
}
public QueryTreeNode groupBy(IOrderBy sc) {
setNeedBuild(true);
this.groups.add(sc);
return this;
}
public QueryTreeNode orderBy(ISelectable c, boolean asc) {
IOrderBy orderBy = ASTNodeFactory.getInstance().createOrderBy();
orderBy.setColumn(c);
orderBy.setDirection(asc);
if (!this.orderBys.contains(orderBy)) {
this.orderBys.add(orderBy);
setNeedBuild(true);
}
return this;
}
public QueryTreeNode orderBy(String o) {
return orderBy(o, true);
}
public QueryTreeNode orderBy(String o, boolean asc) {
IOrderBy orderBy = ASTNodeFactory.getInstance().createOrderBy();
String column = o;
orderBy.setDirection(asc);
return this.orderBy(OptimizerUtils.createColumnFromString(column), orderBy.getDirection());
}
/**
* 多个列时,允许逗号分隔
*/
public QueryTreeNode select(String s) {
s = s.toUpperCase();
List<ISelectable> ss = new ArrayList();
for (String cn : s.split(",")) {
ss.add(OptimizerUtils.createColumnFromString(cn));
}
return this.select(ss);
}
public QueryTreeNode query(String where, String select) {
return this.query(where).select(select);
}
/**
* 设置别名,表级别
*/
public QueryTreeNode setAlias(String string) {
this.alias(string);
return this;
}
/**
* 设置别名,表级别
*/
public QueryTreeNode setSubAlias(String string) {
this.subAlias(string);
return this;
}
public String getSubAlias() {
return subAlias;
}
public boolean isSubQuery() {
return subQuery;
}
public QueryTreeNode setSubQuery(boolean subQuery) {
setNeedBuild(true);
this.subQuery = subQuery;
return this;
}
@Override
public boolean isNeedBuild() {
if (this.needBuild) {
return true;
}
// 如果子查询发生了改变,也需要重新build
for (ASTNode child : this.getChildren()) {
if (child.isNeedBuild()) {
needBuild = true;
return true;
}
}
return false;
}
public QueryTreeNode setConsistent(boolean b) {
this.consistent = b;
return this;
}
public boolean getConsistent() {
return this.consistent;
}
public QUERY_CONCURRENCY getQueryConcurrency() {
return this.queryConcurrency;
}
public QueryTreeNode setQueryConcurrency(QUERY_CONCURRENCY qc) {
this.queryConcurrency = qc;
return this;
}
public QueryTreeNode having(IFilter havingFilter) {
this.havingFilter = havingFilter;
return this;
}
public QueryTreeNode having(String having) {
this.havingFilter = FilterUtils.createFilter(having);
return this;
}
public IFilter getHavingFilter() {
return this.havingFilter;
}
public boolean containsKeyFilter() {
return this.keyFilter != null;
}
public IFilter getOtherJoinOnFilter() {
return otherJoinOnFilter;
}
public QueryTreeNode setOtherJoinOnFilter(IFilter otherJoinOnFilter) {
this.otherJoinOnFilter = otherJoinOnFilter;
return this;
}
public IFilter getAllWhereFilter() {
return allWhereFilter;
}
public QueryTreeNode setAllWhereFilter(IFilter allWhereFilter) {
this.allWhereFilter = allWhereFilter;
return this;
}
public LOCK_MODEL getLockModel() {
return lockModel;
}
public boolean isExistAggregate() {
return isExistAggregate;
}
public QueryTreeNode setExistAggregate(boolean isExistAggregate) {
this.isExistAggregate = isExistAggregate;
return this;
}
// ==================== helper method =================
/**
* <pre>
* distinct和group by的字段顺序打乱的计算结果是等价的,所以可以对此做一些优化
*
* 1. order by和group by同时存在时,并且group by包含了order by所有的字段,调整groupBy的字段顺序符合order by的顺序,多余的字段并下推到order by
* 如: group by c1 c2 c3 order by c2 c1,可优化为:group by c2 c1 c3 order by c2 c1 c3,同时可将order by下推
* 2. 只存在group by,复制group by字段到order by
* </pre>
*/
public List<IOrderBy> getOrderByCombineWithGroupBy() {
// 如果用户没指定order by,则显示index的order by
if (this.getOrderBys() != null && !this.getOrderBys().isEmpty()) {
if (this.getGroupBys() != null && !this.getGroupBys().isEmpty()) {
List<IOrderBy> newOrderBys = new ArrayList<IOrderBy>();
// 首先以order by的顺序,查找group by中对应的字段
for (IOrderBy orderBy : this.getOrderBys()) {
if (findOrderByByColumn(this.getGroupBys(), orderBy.getColumn()) != null) {
newOrderBys.add(orderBy.copy());
} else {
if (newOrderBys.size() == this.getGroupBys().size()) {
// 说明出现order by包含了整个group by
this.setGroupBys(newOrderBys);// 将group by重置一下顺序
}
// group by中不包含order by字段
return this.getOrderBys();
}
}
for (IOrderBy groupBy : this.getGroupBys()) {
if (findOrderByByColumn(newOrderBys, groupBy.getColumn()) == null) {
// 添加下order by中没有的字段
newOrderBys.add(groupBy.copy());
}
}
this.setGroupBys(newOrderBys);// 将group by重置一下顺序
return newOrderBys;
} else {
return this.getOrderBys();
}
} else {
// 没有orderby,复制group by
if (this.getGroupBys() != null && !this.getGroupBys().isEmpty()) {
return OptimizerUtils.copyOrderBys(this.getGroupBys());
}
return null;
}
}
/**
* 尝试查找一个同名的排序字段
*/
protected IOrderBy findOrderByByColumn(List<IOrderBy> orderbys, ISelectable column) {
for (IOrderBy order : orderbys) {
if (order.getColumn().equals(column)) {
return order;
}
}
return null;
}
/**
* 复制数据到目标对象,注意此方法只会复制expression对象的引用
*/
protected void copySelfTo(QueryTreeNode to) {
to.setAlias(this.alias);
to.setSubAlias(this.subAlias);
to.columnsSelected = this.getColumnsSelected();
to.columnsRefered = this.getColumnsRefered();
to.groups = this.getGroupBys();
to.orderBys = this.getOrderBys();
to.whereFilter = (IFilter) (this.whereFilter == null ? null : this.whereFilter.copy());
to.havingFilter = (IFilter) (this.havingFilter == null ? null : havingFilter.copy());
to.keyFilter = (IFilter) (this.keyFilter == null ? null : keyFilter.copy());
to.resultFilter = (IFilter) (this.resultFilter == null ? null : this.resultFilter.copy());
to.allWhereFilter = (IFilter) (this.allWhereFilter == null ? null : this.allWhereFilter.copy());
to.otherJoinOnFilter = (IFilter) (this.otherJoinOnFilter == null ? null : this.otherJoinOnFilter.copy());
to.setLimitFrom(this.limitFrom);
to.setLimitTo(this.limitTo);
to.setNeedBuild(this.needBuild);
to.setSql(this.getSql());
to.setSubQuery(subQuery);
to.setExistAggregate(isExistAggregate);
}
/**
* 复制数据到目标对象,注意此方法会复制expression对象
*/
protected void deepCopySelfTo(QueryTreeNode to) {
to.setAlias(this.alias);
to.setSubAlias(this.subAlias);
to.columnsSelected = OptimizerUtils.copySelectables(this.getColumnsSelected());
to.columnsRefered = OptimizerUtils.copySelectables(this.getColumnsRefered());
to.groups = OptimizerUtils.copyOrderBys(new ArrayList<IOrderBy>(this.getGroupBys()));
to.orderBys = OptimizerUtils.copyOrderBys(new ArrayList<IOrderBy>(this.getOrderBys()));
to.whereFilter = (IFilter) (this.whereFilter == null ? null : this.whereFilter.copy());
to.havingFilter = (IFilter) (this.havingFilter == null ? null : havingFilter.copy());
to.keyFilter = (IFilter) (this.keyFilter == null ? null : keyFilter.copy());
to.resultFilter = (IFilter) (this.resultFilter == null ? null : this.resultFilter.copy());
to.allWhereFilter = (IFilter) (this.allWhereFilter == null ? null : this.allWhereFilter.copy());
to.otherJoinOnFilter = (IFilter) (otherJoinOnFilter == null ? null : otherJoinOnFilter.copy());
to.setLimitFrom(this.getLimitFrom());
to.setLimitTo(this.getLimitTo());
to.setSql(this.getSql());
to.setSubQuery(this.isSubQuery());
to.setNeedBuild(this.isNeedBuild());
to.setExistAggregate(isExistAggregate);
}
}