package com.taobao.tddl.optimizer.core.ast.build; import java.util.ArrayList; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; import com.taobao.tddl.optimizer.core.ASTNodeFactory; import com.taobao.tddl.optimizer.core.ast.ASTNode; import com.taobao.tddl.optimizer.core.ast.QueryTreeNode; import com.taobao.tddl.optimizer.core.ast.query.JoinNode; 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.IFunction; import com.taobao.tddl.optimizer.core.expression.ISelectable; import com.taobao.tddl.optimizer.utils.FilterUtils; /** * @since 5.0.0 */ public class JoinNodeBuilder extends QueryTreeNodeBuilder { private Set<IColumn> columnInAggregate = new HashSet(); public JoinNodeBuilder(JoinNode joinNode){ this.setNode(joinNode); } public JoinNode getNode() { return (JoinNode) super.getNode(); } public void build() { if (this.getNode().isUedForIndexJoinPK()) { return; } this.columnInAggregate.clear(); this.buildSelected(); this.buildJoinKeys(); this.buildWhere(); this.buildGroupBy(); this.buildOrderBy(); this.buildHaving(); this.buildColumnRefered(); this.buildExistAggregate(); } private void buildColumnRefered() { List<ISelectable> columnRefered = new ArrayList(); columnRefered.addAll(this.getNode().getColumnsSelected()); for (IBooleanFilter f : this.getNode().getJoinFilter()) { ISelectable left = (ISelectable) f.getColumn(); ISelectable right = (ISelectable) f.getValue(); if (!columnRefered.contains(left)) { columnRefered.add(left); } if (!columnRefered.contains(right)) { columnRefered.add(right); } } for (IColumn c : this.columnInAggregate) { if (!columnRefered.contains(c)) { columnRefered.add(c); } } this.getNode().setColumnsRefered(columnRefered); } private void buildJoinKeys() { if (this.getNode().isUedForIndexJoinPK()) { return; } List<IBooleanFilter> otherJoinOnFilters = new ArrayList(this.getNode().getJoinFilter().size()); for (IBooleanFilter f : this.getNode().getJoinFilter()) { ISelectable leftKey = null; if (f.getColumn() != null && f.getColumn() instanceof ISelectable) { leftKey = this.getColumnFromOtherNode((ISelectable) f.getColumn(), this.getNode().getLeftNode()); } ISelectable rightKey = null; if (f.getValue() != null && f.getValue() instanceof ISelectable) { rightKey = this.getColumnFromOtherNode((ISelectable) f.getValue(), this.getNode().getRightNode()); } // 可能顺序调换了,重新找一次 if (leftKey == null || rightKey == null) { if (f.getValue() != null && f.getValue() instanceof ISelectable) { leftKey = this.getColumnFromOtherNode((ISelectable) f.getValue(), this.getNode().getLeftNode()); } if (f.getColumn() != null && f.getColumn() instanceof ISelectable) { rightKey = this.getColumnFromOtherNode((ISelectable) f.getColumn(), this.getNode().getRightNode()); } } if (leftKey == null || rightKey == null) { // 可能有以下情况 // id=1,s.id=s.key_id IFilter otherJoinOnFilter = this.getNode().getOtherJoinOnFilter(); otherJoinOnFilter = FilterUtils.and(otherJoinOnFilter, f); this.getNode().setOtherJoinOnFilter(otherJoinOnFilter); otherJoinOnFilters.add(f); continue; } /** * 如果是回表操作,不能把索引的joinKey添加到temp中,否则如果有merge,这个列会被加到sql的select中, * 而导致找不到列 */ if (!this.getNode().isUedForIndexJoinPK()) { f.setColumn(buildSelectable(leftKey)); f.setValue(buildSelectable(rightKey)); } } this.getNode().getJoinFilter().removeAll(otherJoinOnFilters); this.buildFilter(this.getNode().getOtherJoinOnFilter(), false); } /** * 构建列信息 * * @param indexNode */ public void buildSelected() { buildSelectedFromSelectableObject(); } private void buildSelectedFromSelectableObject() { // 如果为空,代表是用* if (this.getNode().getColumnsSelected().isEmpty()) { this.getNode() .getColumnsSelected() .add(ASTNodeFactory.getInstance().createColumn().setColumnName(IColumn.STAR)); } // 如果有 * ,最后需要把*删掉 List<Integer> delete = new LinkedList(); int index = 0; for (ISelectable selected : getNode().getColumnsSelected()) { if (IColumn.STAR.equals(selected.getColumnName())) { delete.add(index); break; } } if (!delete.isEmpty()) { List<ISelectable> columnsWithOutStar = new ArrayList(); for (int i = 0; i < this.getNode().getColumnsSelected().size(); i++) { ISelectable selected = this.getNode().getColumnsSelected().get(i); if (this.getNode().getColumnsSelected().get(i).getColumnName().equals(IColumn.STAR)) { // 遇到*就把所有列再添加一遍 // select *,id这样的语法最后会有两个id列,mysql是这样的 for (ASTNode child : this.getNode().getChildren()) { for (ISelectable selectedFromChild : ((QueryTreeNode) child).getColumnsSelectedForParent()) { // 考虑 // a. SELECT B.* FROM TABLE1 A INNER JOIN TABLE2 B // b. SELECT * FROM TABLE1 A INNER JOIN TABLE2 B if (selected.getTableName() != null && !selected.getTableName().equals(selectedFromChild.getTableName())) { break; } IColumn newS = ASTNodeFactory.getInstance().createColumn(); // 尝试复制子节点的表别名 if (((QueryTreeNode) child).getAlias() != null) { newS.setTableName(((QueryTreeNode) child).getAlias()); } else { newS.setTableName(selectedFromChild.getTableName()); } if (selectedFromChild.getAlias() != null) { newS.setColumnName(selectedFromChild.getAlias()); } else { newS.setColumnName(selectedFromChild.getColumnName()); } columnsWithOutStar.add(newS); } } } else { columnsWithOutStar.add(this.getNode().getColumnsSelected().get(i)); } } this.getNode().select(columnsWithOutStar); } for (int i = 0; i < getNode().getColumnsSelected().size(); i++) { getNode().getColumnsSelected().set(i, this.buildSelectable(getNode().getColumnsSelected().get(i))); } } public ISelectable getSelectableFromChild(ISelectable c) { if (c instanceof IFunction) { return c; } if (IColumn.STAR.equals(c.getColumnName())) { return c; } QueryTreeNode left = this.getNode().getLeftNode(); QueryTreeNode right = this.getNode().getRightNode(); ISelectable resFromLeft = null; ISelectable resFromRight = null; boolean isLeft = left.hasColumn(c); boolean isRight = right.hasColumn(c); if (isLeft && isRight) { throw new IllegalArgumentException("Column '" + c.getColumnName() + "' is ambiguous in JoinNode"); } if (isLeft) {// 可能在select/from中 resFromLeft = this.getColumnFromOtherNode(c, left); if (resFromLeft == null) {// 如果不在select中,添加到select进行join传递 left.addColumnsSelected(c.copy()); resFromLeft = this.getColumnFromOtherNode(c, left); } } if (isRight) {// 可能在select/from中 resFromRight = this.getColumnFromOtherNode(c, right); if (resFromRight == null) {// 如果不在select中,添加到select进行join传递 right.addColumnsSelected(c.copy()); resFromRight = this.getColumnFromOtherNode(c, right); } } return resFromLeft == null ? resFromRight : resFromLeft; } public void buildFunction(IFunction f) { if (f.getArgs().size() == 0) { return; } List<Object> args = f.getArgs(); for (int i = 0; i < args.size(); i++) { if (args.get(i) instanceof ISelectable) { args.set(i, this.buildSelectable((ISelectable) args.get(i))); if (IFunction.FunctionType.Aggregate.equals(f.getFunctionType()) && (args.get(i) instanceof IColumn)) { this.columnInAggregate.add((IColumn) args.get(i)); } } } } }