Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

planner: eliminate if null on non null column #7924

Merged
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions cmd/explaintest/r/explain_easy.result
Original file line number Diff line number Diff line change
Expand Up @@ -385,3 +385,40 @@ Projection_5 8000.00 root test.ta.a
└─TableReader_9 10000.00 root data:TableScan_8
└─TableScan_8 10000.00 cop table:ta, range:[-inf,+inf], keep order:false, stats:pseudo
rollback;
drop table if exists t;
create table t(a int, nb int not null, nc int not null);
explain select ifnull(a, 0) from t;
id count task operator info
Projection_3 10000.00 root ifnull(test.t.a, 0)
└─TableReader_5 10000.00 root data:TableScan_4
└─TableScan_4 10000.00 cop table:t, range:[-inf,+inf], keep order:false, stats:pseudo
explain select ifnull(nb, 0) from t;
id count task operator info
TableReader_5 10000.00 root data:TableScan_4
└─TableScan_4 10000.00 cop table:t, range:[-inf,+inf], keep order:false, stats:pseudo
explain select ifnull(nb, 0), ifnull(nc, 0) from t;
id count task operator info
TableReader_5 10000.00 root data:TableScan_4
└─TableScan_4 10000.00 cop table:t, range:[-inf,+inf], keep order:false, stats:pseudo
explain select ifnull(a, 0), ifnull(nb, 0) from t;
id count task operator info
Projection_3 10000.00 root ifnull(test.t.a, 0), test.t.nb
└─TableReader_5 10000.00 root data:TableScan_4
└─TableScan_4 10000.00 cop table:t, range:[-inf,+inf], keep order:false, stats:pseudo
explain select ifnull(nb, 0), ifnull(nb, 0) from t;
id count task operator info
Projection_3 10000.00 root test.t.nb, test.t.nb
└─TableReader_5 10000.00 root data:TableScan_4
└─TableScan_4 10000.00 cop table:t, range:[-inf,+inf], keep order:false, stats:pseudo
explain select 1+ifnull(nb, 0) from t;
id count task operator info
Projection_3 10000.00 root plus(1, test.t.nb)
└─TableReader_5 10000.00 root data:TableScan_4
└─TableScan_4 10000.00 cop table:t, range:[-inf,+inf], keep order:false, stats:pseudo
explain select 1+ifnull(a, 0) from t;
id count task operator info
Projection_3 10000.00 root plus(1, ifnull(test.t.a, 0))
└─TableReader_5 10000.00 root data:TableScan_4
└─TableScan_4 10000.00 cop table:t, range:[-inf,+inf], keep order:false, stats:pseudo
drop table if exists t;
drop table if exists t;
12 changes: 12 additions & 0 deletions cmd/explaintest/t/explain_easy.test
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,15 @@ begin;
insert tb values ('1');
explain select * from ta where a = 1;
rollback;

# https://github.com/pingcap/tidb/issues/7918
drop table if exists t;
create table t(a int, nb int not null, nc int not null);
explain select ifnull(a, 0) from t;
explain select ifnull(nb, 0) from t;
explain select ifnull(nb, 0), ifnull(nc, 0) from t;
explain select ifnull(a, 0), ifnull(nb, 0) from t;
explain select ifnull(nb, 0), ifnull(nb, 0) from t;
explain select 1+ifnull(nb, 0) from t;
explain select 1+ifnull(a, 0) from t;
drop table if exists t;
6 changes: 6 additions & 0 deletions expression/builtin.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,10 @@ func (b *baseBuiltinFunc) getArgs() []Expression {
return b.args
}

func (b *baseBuiltinFunc) setArgs(args []Expression) {
b.args = args
}

func (b *baseBuiltinFunc) evalInt(row chunk.Row) (int64, bool, error) {
panic("baseBuiltinFunc.evalInt() should never be called.")
}
Expand Down Expand Up @@ -274,6 +278,8 @@ type builtinFunc interface {
evalJSON(row chunk.Row) (val json.BinaryJSON, isNull bool, err error)
// getArgs returns the arguments expressions.
getArgs() []Expression
// setArgs set the arguments expressions to builtFunc.
setArgs(args []Expression)
// equal check if this function equals to another function.
equal(builtinFunc) bool
// getCtx returns this function's context.
Expand Down
5 changes: 5 additions & 0 deletions expression/scalar_function.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ func (sf *ScalarFunction) GetArgs() []Expression {
return sf.Function.getArgs()
}

// SetArgs sets arguments of function.
func (sf *ScalarFunction) SetArgs(args []Expression) {
sf.Function.setArgs(args)
}

// GetCtx gets the context of function.
func (sf *ScalarFunction) GetCtx() sessionctx.Context {
return sf.Function.getCtx()
Expand Down
33 changes: 33 additions & 0 deletions planner/core/logical_plan_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -576,6 +576,38 @@ func (b *PlanBuilder) buildProjectionField(id, position int, field *ast.SelectFi
}
}

func eliminateIfNullOnNotNullCol(p LogicalPlan, expr expression.Expression) expression.Expression {
ds, isDs := p.(*DataSource)
if !isDs {
return expr
}

scalarExpr, isScalarFunc := expr.(*expression.ScalarFunction)
if !isScalarFunc {
return expr
}
exprChildren := scalarExpr.GetArgs()
for i := 0; i < len(exprChildren); i++ {
exprChildren[i] = eliminateIfNullOnNotNullCol(p, exprChildren[i])
}

if scalarExpr.FuncName.L == ast.Ifnull {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about:

if scalarExpr.FuncName.L != ast.Ifnull {
	return expr
}

colRef, isColRef := exprChildren[0].(*expression.Column)
if !isColRef {
return expr
}

colInfo := model.FindColumnInfo(ds.Columns, colRef.ColName.L)
if !mysql.HasNotNullFlag(colInfo.Flag) {
return expr
}

return colRef
}
scalarExpr.SetArgs(exprChildren)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this can be removed.

return scalarExpr
}

// buildProjection returns a Projection plan and non-aux columns length.
func (b *PlanBuilder) buildProjection(p LogicalPlan, fields []*ast.SelectField, mapper map[*ast.AggregateFuncExpr]int) (LogicalPlan, int, error) {
b.optFlag |= flagEliminateProjection
Expand All @@ -585,6 +617,7 @@ func (b *PlanBuilder) buildProjection(p LogicalPlan, fields []*ast.SelectField,
oldLen := 0
for _, field := range fields {
newExpr, np, err := b.rewrite(field.Expr, p, mapper, true)
newExpr = eliminateIfNullOnNotNullCol(p, newExpr)
if err != nil {
return nil, 0, errors.Trace(err)
}
Expand Down