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

expression: refactor constant folding for IF&IFNULL (#9094) #9351

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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
18 changes: 10 additions & 8 deletions expression/constant_fold.go
Expand Up @@ -41,7 +41,10 @@ func ifFoldHandler(expr *ScalarFunction) (Expression, bool) {
if constArg, isConst := foldedArg0.(*Constant); isConst {
arg0, isNull0, err := constArg.EvalInt(expr.Function.getCtx(), chunk.Row{})
if err != nil {
log.Warnf("fold constant %s: %s", expr.ExplainInfo(), err.Error())
// Failed to fold this expr to a constant, print the DEBUG log and
// return the original expression to let the error to be evaluated
// again, in that time, the error is returned to the client.
log.Debugf("fold constant %s: %s", expr.ExplainInfo(), err.Error())
return expr, false
}
if !isNull0 && arg0 != 0 {
Expand All @@ -59,16 +62,15 @@ func ifFoldHandler(expr *ScalarFunction) (Expression, bool) {

func ifNullFoldHandler(expr *ScalarFunction) (Expression, bool) {
args := expr.GetArgs()
foldedArg0, _ := foldConstant(args[0])
foldedArg0, isDeferred := foldConstant(args[0])
if constArg, isConst := foldedArg0.(*Constant); isConst {
_, isNull0, err := constArg.EvalInt(expr.Function.getCtx(), chunk.Row{})
if err != nil {
log.Warnf("fold constant %s: %s", expr.ExplainInfo(), err.Error())
return expr, false
}
if isNull0 == true {
// Only check constArg.Value here. Because deferred expression is
// evaluated to constArg.Value after foldConstant(args[0]), it's not
// needed to be checked.
if constArg.Value.IsNull() {
return foldConstant(args[1])
}
return constArg, isDeferred
}
isDeferredConst := false
expr.GetArgs()[1], isDeferredConst = foldConstant(args[1])
Expand Down
35 changes: 35 additions & 0 deletions expression/constant_fold_test.go
@@ -0,0 +1,35 @@
// Copyright 2019 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

package expression_test

import (
. "github.com/pingcap/check"
"github.com/pingcap/tidb/util/testkit"
)

func (s *testIntegrationSuite) TestFoldIfNull(c *C) {
tk := testkit.NewTestKit(c, s.store)
tk.MustExec(`use test;`)
tk.MustExec(`drop table if exists t;`)
tk.MustExec(`create table t(a bigint, b bigint);`)
tk.MustExec(`insert into t values(1, 1);`)
tk.MustQuery(`desc select ifnull("aaaa", a) from t;`).Check(testkit.Rows(
`Projection_3 10000.00 root "aaaa"`,
`└─TableReader_5 10000.00 root data:TableScan_4`,
` └─TableScan_4 10000.00 cop table:t, range:[-inf,+inf], keep order:false, stats:pseudo`,
))
tk.MustQuery(`show warnings;`).Check(testkit.Rows())
tk.MustQuery(`select ifnull("aaaa", a) from t;`).Check(testkit.Rows("aaaa"))
tk.MustQuery(`show warnings;`).Check(testkit.Rows())
}