Repository: pingcap/tidb
File: pkg/planner/core/operator/logicalop/logical_join.go (Go)

Code before:
	leftCond = constraint.DeleteTrueExprsBySchema(evalCtx, leftChild.Schema(), leftCond)
	leftRet, lCh, err := leftChild.PredicatePushDown(leftCond)
	if err != nil {
		return nil, nil, err
	}
	rightRet, rCh, err := rightChild.PredicatePushDown(rightCond)
	if err != nil {
		return nil, nil, err
	}
	AddSelection(p, lCh, leftRet, 0)
	AddSelection(p, rCh, rightRet, 1)
	p.updateEQCond()
	ruleutil.BuildKeyInfoPortal(p)
	newnChild, err := p.SemiJoinRewrite()
	return ret, newnChild, err
}

func (p *LogicalJoin) normalizeJoinConditionsForOuterJoin() {
	if len(p.OtherConditions) == 0 {
		return
	}
	// Outer join ON conditions are not simplified through predicate pushdown.
	// However, we still need to eliminate obvious logical constants in OtherConditions
	// (e.g. "a = b OR 0") to avoid losing join keys.
	p.OtherConditions = ruleutil.ApplyPredicateSimplificationForJoin(
		p.SCtx(),
		p.OtherConditions,
		p.Children()[0].Schema(),
		p.Children()[1].Schema(),
		false,
		nil,
	)
}

// simplifyOuterJoin transforms "LeftOuterJoin/RightOuterJoin" to "InnerJoin" if possible.
func simplifyOuterJoin(p *LogicalJoin, predicates []expression.Expression) {
	if p.JoinType != base.LeftOuterJoin && p.JoinType != base.RightOuterJoin && p.JoinType != base.InnerJoin {
		return
	}

	innerTable := p.children[0]
	outerTable := p.children[1]
	if p.JoinType == base.LeftOuterJoin {
		innerTable, outerTable = outerTable, innerTable
	}

	if p.JoinType == base.InnerJoin {
		return
	}
	// then simplify embedding outer join.
	canBeSimplified := false

Review comment (refactor):
Do we need to call this function for other join types, like semi/anti/inner?
Also we can move this function call inside `PredicatePushDown`, becase there is no much logic, and a new function seems meanless.

Code after:
		_, leftPushCond, rightPushCond, _ = p.extractOnCondition(predicates, true, true)
		// Do not derive `is not null` for anti join, since it may cause wrong results.
		// For example:
		// `select * from t t1 where t1.a not in (select b from t t2)` does not imply `t2.b is not null`,
		// `select * from t t1 where t1.a not in (select a from t t2 where t1.b = t2.b` does not imply `t1.b is not null`,
		// `select * from t t1 where not exists (select * from t t2 where t2.a = t1.a)` does not imply `t1.a is not null`,
		leftCond = leftPushCond
		rightCond = append(p.RightConditions, rightPushCond...)
		p.RightConditions = nil
	}
	leftCond = expression.RemoveDupExprs(leftCond)
	rightCond = expression.RemoveDupExprs(rightCond)
	evalCtx := p.SCtx().GetExprCtx().GetEvalCtx()
	children := p.Children()
	rightChild := children[1]
	leftChild := children[0]
	rightCond = constraint.DeleteTrueExprsBySchema(evalCtx, rightChild.Schema(), rightCond)
	leftCond = constraint.DeleteTrueExprsBySchema(evalCtx, leftChild.Schema(), leftCond)
	leftRet, lCh, err := leftChild.PredicatePushDown(leftCond)
	if err != nil {
		return nil, nil, err
	}
	rightRet, rCh, err := rightChild.PredicatePushDown(rightCond)
	if err != nil {
		return nil, nil, err
	}
	AddSelection(p, lCh, leftRet, 0)
	AddSelection(p, rCh, rightRet, 1)
	p.updateEQCond()
	ruleutil.BuildKeyInfoPortal(p)
	newnChild, err := p.SemiJoinRewrite()
	return ret, newnChild, err
}

// simplifyOuterJoin transforms "LeftOuterJoin/RightOuterJoin" to "InnerJoin" if possible.
func simplifyOuterJoin(p *LogicalJoin, predicates []expression.Expression) {
	if p.JoinType != base.LeftOuterJoin && p.JoinType != base.RightOuterJoin && p.JoinType != base.InnerJoin {
		return
	}

	innerTable := p.children[0]
	outerTable := p.children[1]
	if p.JoinType == base.LeftOuterJoin {
		innerTable, outerTable = outerTable, innerTable
	}

	if p.JoinType == base.InnerJoin {
		return
	}
	// then simplify embedding outer join.
	canBeSimplified := false