// PredicatePushDown implements LogicalPlan PredicatePushDown interface. func (p *Join) PredicatePushDown(predicates []expression.Expression) (ret []expression.Expression, retPlan LogicalPlan, err error) { //TODO: add null rejecter. var leftCond, rightCond []expression.Expression retPlan = p leftPlan := p.GetChildByIndex(0).(LogicalPlan) rightPlan := p.GetChildByIndex(1).(LogicalPlan) equalCond, leftPushCond, rightPushCond, otherCond := extractOnCondition(predicates, leftPlan, rightPlan) if p.JoinType == LeftOuterJoin { rightCond = p.RightConditions leftCond = leftPushCond ret = append(expression.ScalarFuncs2Exprs(equalCond), otherCond...) ret = append(ret, rightPushCond...) } else if p.JoinType == RightOuterJoin { leftCond = p.LeftConditions rightCond = rightPushCond ret = append(expression.ScalarFuncs2Exprs(equalCond), otherCond...) ret = append(ret, leftPushCond...) } else { leftCond = append(p.LeftConditions, leftPushCond...) rightCond = append(p.RightConditions, rightPushCond...) } leftRet, _, err1 := leftPlan.PredicatePushDown(leftCond) if err1 != nil { return nil, nil, errors.Trace(err1) } rightRet, _, err2 := rightPlan.PredicatePushDown(rightCond) if err2 != nil { return nil, nil, errors.Trace(err2) } if len(leftRet) > 0 { err2 = addSelection(p, leftPlan, leftRet, p.allocator) if err2 != nil { return nil, nil, errors.Trace(err2) } } if len(rightRet) > 0 { err2 = addSelection(p, rightPlan, rightRet, p.allocator) if err2 != nil { return nil, nil, errors.Trace(err2) } } if p.JoinType == InnerJoin { p.EqualConditions = append(p.EqualConditions, equalCond...) p.OtherConditions = append(p.OtherConditions, otherCond...) } return }
// PredicatePushDown implements LogicalPlan PredicatePushDown interface. func (p *Join) PredicatePushDown(predicates []expression.Expression) (ret []expression.Expression, retPlan LogicalPlan, err error) { //TODO: add null rejecter. groups, valid := tryToGetJoinGroup(p) if valid { e := joinReOrderSolver{allocator: p.allocator} e.reorderJoin(groups, predicates) newJoin := e.resultJoin parent := p.parents[0] newJoin.SetParents(parent) parent.ReplaceChild(p, newJoin) return newJoin.PredicatePushDown(predicates) } var leftCond, rightCond []expression.Expression retPlan = p leftPlan := p.GetChildByIndex(0).(LogicalPlan) rightPlan := p.GetChildByIndex(1).(LogicalPlan) equalCond, leftPushCond, rightPushCond, otherCond := extractOnCondition(predicates, leftPlan, rightPlan) if p.JoinType == LeftOuterJoin || p.JoinType == SemiJoinWithAux { rightCond = p.RightConditions p.RightConditions = nil leftCond = leftPushCond ret = append(expression.ScalarFuncs2Exprs(equalCond), otherCond...) ret = append(ret, rightPushCond...) } else if p.JoinType == RightOuterJoin { leftCond = p.LeftConditions p.LeftConditions = nil rightCond = rightPushCond ret = append(expression.ScalarFuncs2Exprs(equalCond), otherCond...) ret = append(ret, leftPushCond...) } else { leftCond = append(p.LeftConditions, leftPushCond...) rightCond = append(p.RightConditions, rightPushCond...) p.LeftConditions = nil p.RightConditions = nil } leftRet, _, err1 := leftPlan.PredicatePushDown(leftCond) if err1 != nil { return nil, nil, errors.Trace(err1) } rightRet, _, err2 := rightPlan.PredicatePushDown(rightCond) if err2 != nil { return nil, nil, errors.Trace(err2) } if len(leftRet) > 0 { err2 = addSelection(p, leftPlan, leftRet, p.allocator) if err2 != nil { return nil, nil, errors.Trace(err2) } } if len(rightRet) > 0 { err2 = addSelection(p, rightPlan, rightRet, p.allocator) if err2 != nil { return nil, nil, errors.Trace(err2) } } if p.JoinType == InnerJoin { p.EqualConditions = append(p.EqualConditions, equalCond...) p.OtherConditions = append(p.OtherConditions, otherCond...) } return }
// PredicatePushDown implements LogicalPlan PredicatePushDown interface. func (p *Join) PredicatePushDown(predicates []expression.Expression) (ret []expression.Expression, retPlan LogicalPlan, err error) { err = outerJoinSimplify(p, predicates) if err != nil { return nil, nil, errors.Trace(err) } groups, valid := tryToGetJoinGroup(p) if valid { e := joinReOrderSolver{allocator: p.allocator} e.reorderJoin(groups, predicates) newJoin := e.resultJoin parent := p.parents[0] newJoin.SetParents(parent) parent.ReplaceChild(p, newJoin) return newJoin.PredicatePushDown(predicates) } var leftCond, rightCond []expression.Expression retPlan = p leftPlan := p.GetChildByIndex(0).(LogicalPlan) rightPlan := p.GetChildByIndex(1).(LogicalPlan) var ( equalCond []*expression.ScalarFunction leftPushCond, rightPushCond, otherCond []expression.Expression ) if p.JoinType != InnerJoin { equalCond, leftPushCond, rightPushCond, otherCond = extractOnCondition(predicates, leftPlan, rightPlan) } else { tempCond := make([]expression.Expression, 0, len(p.LeftConditions)+len(p.RightConditions)+len(p.EqualConditions)+len(p.OtherConditions)) tempCond = append(tempCond, p.LeftConditions...) tempCond = append(tempCond, p.RightConditions...) tempCond = append(tempCond, expression.ScalarFuncs2Exprs(p.EqualConditions)...) tempCond = append(tempCond, p.OtherConditions...) if len(tempCond) != 0 { tempCond = append(tempCond, predicates...) equalCond, leftPushCond, rightPushCond, otherCond = extractOnCondition(propagateConstant(tempCond), leftPlan, rightPlan) } else { // "on" is not used. equalCond, leftPushCond, rightPushCond, otherCond = extractOnCondition(predicates, leftPlan, rightPlan) } } switch p.JoinType { case LeftOuterJoin, SemiJoinWithAux: rightCond = p.RightConditions p.RightConditions = nil leftCond = leftPushCond ret = append(expression.ScalarFuncs2Exprs(equalCond), otherCond...) ret = append(ret, rightPushCond...) case RightOuterJoin: leftCond = p.LeftConditions p.LeftConditions = nil rightCond = rightPushCond ret = append(expression.ScalarFuncs2Exprs(equalCond), otherCond...) ret = append(ret, leftPushCond...) case SemiJoin: equalCond, leftPushCond, rightPushCond, otherCond = extractOnCondition(predicates, leftPlan, rightPlan) leftCond = propagateConstant(append(p.LeftConditions, leftPushCond...)) rightCond = propagateConstant(append(p.RightConditions, rightPushCond...)) p.LeftConditions = nil p.RightConditions = nil case InnerJoin: p.LeftConditions = nil p.RightConditions = nil p.EqualConditions = equalCond p.OtherConditions = otherCond leftCond = leftPushCond rightCond = rightPushCond } leftRet, _, err1 := leftPlan.PredicatePushDown(leftCond) if err1 != nil { return nil, nil, errors.Trace(err1) } rightRet, _, err2 := rightPlan.PredicatePushDown(rightCond) if err2 != nil { return nil, nil, errors.Trace(err2) } if len(leftRet) > 0 { err2 = addSelection(p, leftPlan, leftRet, p.allocator) if err2 != nil { return nil, nil, errors.Trace(err2) } } if len(rightRet) > 0 { err2 = addSelection(p, rightPlan, rightRet, p.allocator) if err2 != nil { return nil, nil, errors.Trace(err2) } } return }
// predicatePushDown applies predicate push down to all kinds of plans, except aggregation and union. func (b *planBuilder) predicatePushDown(p Plan, predicates []expression.Expression) (ret []expression.Expression, err error) { switch v := p.(type) { case *NewTableScan: return predicates, nil case *Selection: conditions := v.Conditions retConditions, err1 := b.predicatePushDown(p.GetChildByIndex(0), append(conditions, predicates...)) if err1 != nil { return nil, errors.Trace(err1) } if len(retConditions) > 0 { v.Conditions = retConditions } else { if len(p.GetParents()) == 0 { return ret, nil } err1 = RemovePlan(p) if err1 != nil { return nil, errors.Trace(err1) } } return case *Join: //TODO: add null rejecter. var leftCond, rightCond []expression.Expression leftPlan := v.GetChildByIndex(0) rightPlan := v.GetChildByIndex(1) equalCond, leftPushCond, rightPushCond, otherCond := extractOnCondition(predicates, leftPlan, rightPlan) if v.JoinType == LeftOuterJoin { rightCond = v.RightConditions leftCond = leftPushCond ret = append(expression.ScalarFuncs2Exprs(equalCond), otherCond...) ret = append(ret, rightPushCond...) } else if v.JoinType == RightOuterJoin { leftCond = v.LeftConditions rightCond = rightPushCond ret = append(expression.ScalarFuncs2Exprs(equalCond), otherCond...) ret = append(ret, leftPushCond...) } else { leftCond = append(v.LeftConditions, leftPushCond...) rightCond = append(v.RightConditions, rightPushCond...) } leftRet, err1 := b.predicatePushDown(leftPlan, leftCond) if err1 != nil { return nil, errors.Trace(err1) } rightRet, err2 := b.predicatePushDown(rightPlan, rightCond) if err2 != nil { return nil, errors.Trace(err2) } if len(leftRet) > 0 { err2 = b.addSelection(p, leftPlan, leftRet) if err2 != nil { return nil, errors.Trace(err2) } } if len(rightRet) > 0 { err2 = b.addSelection(p, rightPlan, rightRet) if err2 != nil { return nil, errors.Trace(err2) } } if v.JoinType == InnerJoin { v.EqualConditions = append(v.EqualConditions, equalCond...) v.OtherConditions = append(v.OtherConditions, otherCond...) } return case *Projection: if len(v.GetChildren()) == 0 { return predicates, nil } var push []expression.Expression for _, cond := range predicates { canSubstitute := true extractedCols, _ := extractColumn(cond, nil, nil) for _, col := range extractedCols { id := v.GetSchema().GetIndex(col) if _, ok := v.Exprs[id].(*expression.ScalarFunction); ok { canSubstitute = false break } } if canSubstitute { push = append(push, columnSubstitute(cond, v.GetSchema(), v.Exprs)) } else { ret = append(ret, cond) } } restConds, err1 := b.predicatePushDown(v.GetChildByIndex(0), push) if err1 != nil { return nil, errors.Trace(err1) } if len(restConds) > 0 { err1 = b.addSelection(v, v.GetChildByIndex(0), restConds) if err1 != nil { return nil, errors.Trace(err1) } } return case *NewSort, *Limit, *Distinct: rest, err1 := b.predicatePushDown(p.GetChildByIndex(0), predicates) if err1 != nil { return nil, errors.Trace(err1) } if len(rest) > 0 { err1 = b.addSelection(p, p.GetChildByIndex(0), rest) if err1 != nil { return nil, errors.Trace(err1) } } return case *Union: for _, proj := range v.Selects { newExprs := make([]expression.Expression, 0, len(predicates)) for _, cond := range predicates { newCond := columnSubstitute(cond.DeepCopy(), v.GetSchema(), expression.Schema2Exprs(proj.GetSchema())) newExprs = append(newExprs, newCond) } retCond, err := b.predicatePushDown(proj, newExprs) if err != nil { return nil, errors.Trace(err) } if len(retCond) != 0 { b.addSelection(v, proj, retCond) } } return //TODO: support aggregation, apply. case *Aggregation, *Simple, *Apply: return predicates, nil default: log.Warnf("Unknown Type %T in Predicate Pushdown", v) return predicates, nil } }