Skip to content

Commit

Permalink
expression: constant propagation for outer join don't prop control fu…
Browse files Browse the repository at this point in the history
…nctions (#15855) (#16702)

Signed-off-by: sre-bot <sre-bot@pingcap.com>

Co-authored-by: Yiding Cui <winoros@gmail.com>
Co-authored-by: ti-srebot <66930949+ti-srebot@users.noreply.github.com>
  • Loading branch information
3 people authored Jun 28, 2020
1 parent 073a51e commit e0950dc
Show file tree
Hide file tree
Showing 3 changed files with 345 additions and 5 deletions.
17 changes: 12 additions & 5 deletions expression/constant_propagation.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ func validEqualCond(cond Expression) (*Column, *Constant) {
// for 'a, b, a < 3', it returns 'true, false, b < 3'
// for 'a, b, sin(a) + cos(a) = 5', it returns 'true, false, returns sin(b) + cos(b) = 5'
// for 'a, b, cast(a) < rand()', it returns 'false, true, cast(a) < rand()'
func tryToReplaceCond(ctx sessionctx.Context, src *Column, tgt *Column, cond Expression) (bool, bool, Expression) {
func tryToReplaceCond(ctx sessionctx.Context, src *Column, tgt *Column, cond Expression, rejectControl bool) (bool, bool, Expression) {
sf, ok := cond.(*ScalarFunction)
if !ok {
return false, false, cond
Expand All @@ -108,6 +108,13 @@ func tryToReplaceCond(ctx sessionctx.Context, src *Column, tgt *Column, cond Exp
if _, ok := inequalFunctions[sf.FuncName.L]; ok {
return false, true, cond
}
// See https://github.com/pingcap/tidb/issues/15782. The control function's result may rely on the original nullable
// information of the outer side column. Its args cannot be replaced easily.
// A more strict check is that after we replace the arg. We check the nullability of the new expression.
// But we haven't maintained it yet, so don't replace the arg of the control function currently.
if rejectControl && (sf.FuncName.L == ast.Ifnull || sf.FuncName.L == ast.If || sf.FuncName.L == ast.Case) {
return false, false, cond
}
for idx, expr := range sf.GetArgs() {
if src.Equal(nil, expr) {
replaced = true
Expand All @@ -117,7 +124,7 @@ func tryToReplaceCond(ctx sessionctx.Context, src *Column, tgt *Column, cond Exp
}
args[idx] = tgt
} else {
subReplaced, isNonDeterministic, subExpr := tryToReplaceCond(ctx, src, tgt, expr)
subReplaced, isNonDeterministic, subExpr := tryToReplaceCond(ctx, src, tgt, expr, rejectControl)
if isNonDeterministic {
return false, true, cond
} else if subReplaced {
Expand Down Expand Up @@ -216,11 +223,11 @@ func (s *propConstSolver) propagateColumnEQ() {
continue
}
cond := s.conditions[k]
replaced, _, newExpr := tryToReplaceCond(s.ctx, coli, colj, cond)
replaced, _, newExpr := tryToReplaceCond(s.ctx, coli, colj, cond, false)
if replaced {
s.conditions = append(s.conditions, newExpr)
}
replaced, _, newExpr = tryToReplaceCond(s.ctx, colj, coli, cond)
replaced, _, newExpr = tryToReplaceCond(s.ctx, colj, coli, cond, false)
if replaced {
s.conditions = append(s.conditions, newExpr)
}
Expand Down Expand Up @@ -458,7 +465,7 @@ func (s *propOuterJoinConstSolver) deriveConds(outerCol, innerCol *Column, schem
visited[k+offset] = true
continue
}
replaced, _, newExpr := tryToReplaceCond(s.ctx, outerCol, innerCol, cond)
replaced, _, newExpr := tryToReplaceCond(s.ctx, outerCol, innerCol, cond, true)
if replaced {
s.joinConds = append(s.joinConds, newExpr)
}
Expand Down
41 changes: 41 additions & 0 deletions expression/testdata/expression_suite_in.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
[
{
"name": "TestOuterJoinPropConst",
"cases": [
// Positive tests.
"explain select * from t1 left join t2 on t1.a > t2.a and t1.a = 1",
"explain select * from t1 left join t2 on t1.a > t2.a where t1.a = 1",
"explain select * from t1 left join t2 on t1.a = t2.a and t1.a > 1",
"explain select * from t1 left join t2 on t1.a = t2.a where t1.a > 1",
"explain select * from t1 right join t2 on t1.a > t2.a where t2.a = 1",
"explain select * from t1 right join t2 on t1.a = t2.a where t2.a > 1",
"explain select * from t1 right join t2 on t1.a = t2.a and t2.a > 1",
"explain select * from t1 right join t2 on t1.a > t2.a and t2.a = 1",
// Negative tests.
"explain select * from t1 left join t2 on t1.a = t2.a and t2.a > 1",
"explain select * from t1 left join t2 on t1.a > t2.a and t2.a = 1",
"explain select * from t1 right join t2 on t1.a > t2.a and t1.a = 1",
"explain select * from t1 right join t2 on t1.a = t2.a and t1.a > 1",
"explain select * from t1 left join t2 on t1.a = t1.b and t1.a > 1",
"explain select * from t1 left join t2 on t2.a = t2.b and t2.a > 1",
// Constant equal condition merge in outer join.
"explain select * from t1 left join t2 on true where t1.a = 1 and false",
"explain select * from t1 left join t2 on true where t1.a = 1 and null",
"explain select * from t1 left join t2 on true where t1.a = null",
"explain select * from t1 left join t2 on true where t1.a = 1 and t1.a = 2",
"explain select * from t1 left join t2 on true where t1.a = 1 and t1.a = 1",
"explain select * from t1 left join t2 on false",
"explain select * from t1 right join t2 on false",
"explain select * from t1 left join t2 on t1.a = 1 and t1.a = 2",
"explain select * from t1 left join t2 on t1.a =1 where t1.a = 2",
"explain select * from t1 left join t2 on t2.a = 1 and t2.a = 2",
// Constant propagation for DNF in outer join.
"explain select * from t1 left join t2 on t1.a = 1 or (t1.a = 2 and t1.a = 3)",
"explain select * from t1 left join t2 on true where t1.a = 1 or (t1.a = 2 and t1.a = 3)",
// Constant propagation over left outer semi join, filter with aux column should not be derived.
"explain select * from t1 where t1.b > 1 or t1.b in (select b from t2)",
// Don't propagate for the control function.
"explain select * from t1 left join t2 on t1.a = t2.a where ifnull(t2.b, t1.a) = 1"
]
}
]
Loading

0 comments on commit e0950dc

Please sign in to comment.