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: fix incorrect collation when cast non-string type arg to string type #19186

Merged
merged 9 commits into from
Aug 19, 2020
3 changes: 1 addition & 2 deletions expression/builtin_cast.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import (

"github.com/pingcap/errors"
"github.com/pingcap/parser/ast"
"github.com/pingcap/parser/charset"
"github.com/pingcap/parser/model"
"github.com/pingcap/parser/mysql"
"github.com/pingcap/parser/terror"
Expand Down Expand Up @@ -1873,7 +1872,7 @@ func WrapWithCastAsString(ctx sessionctx.Context, expr Expression) Expression {
argLen = mysql.MaxIntWidth
}
tp := types.NewFieldType(mysql.TypeVarString)
tp.Charset, tp.Collate = charset.GetDefaultCharsetAndCollate()
tp.Charset, tp.Collate = expr.CharsetAndCollation(ctx)
tp.Flen, tp.Decimal = argLen, types.UnspecifiedLength
return BuildCastFunction(ctx, expr, tp)
}
Expand Down
8 changes: 7 additions & 1 deletion expression/collation.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,12 +151,18 @@ func deriveCoercibilityForScarlarFunc(sf *ScalarFunction) Coercibility {
if !types.IsString(sf.RetType.Tp) {
return CoercibilityNumeric
}
coer := CoercibilityCoercible
coer := CoercibilityIgnorable
for _, arg := range sf.GetArgs() {
if arg.Coercibility() < coer {
coer = arg.Coercibility()
}
}

// it is weird if a ScalarFunction is CoercibilityNumeric but return string type
if coer == CoercibilityNumeric {
xiongjiwei marked this conversation as resolved.
Show resolved Hide resolved
return CoercibilityCoercible
}

return coer
}

Expand Down
7 changes: 7 additions & 0 deletions expression/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6953,7 +6953,14 @@ func (s *testIntegrationSerialSuite) TestIssue19116(c *C) {
defer collate.SetNewCollationEnabledForTest(false)

tk := testkit.NewTestKit(c, s.store)
tk.MustExec("set names utf8mb4 collate utf8mb4_general_ci;")
tk.MustQuery("select collation(concat(1 collate `binary`));").Check(testkit.Rows("binary"))
tk.MustQuery("select coercibility(concat(1 collate `binary`));").Check(testkit.Rows("0"))
tk.MustQuery("select collation(concat(NULL,NULL));").Check(testkit.Rows("binary"))
tk.MustQuery("select coercibility(concat(NULL,NULL));").Check(testkit.Rows("6"))
tk.MustQuery("select collation(concat(1,1));").Check(testkit.Rows("utf8mb4_general_ci"))
tk.MustQuery("select coercibility(concat(1,1));").Check(testkit.Rows("4"))
tk.MustQuery("select collation(1);").Check(testkit.Rows("binary"))
tk.MustQuery("select coercibility(1);").Check(testkit.Rows("5"))
tk.MustQuery("select coercibility(1=1);").Check(testkit.Rows("5"))
}
1 change: 1 addition & 0 deletions expression/simple_rewriter.go
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@ func (sr *simpleRewriter) Leave(originInNode ast.Node) (retNode ast.Node, ok boo
arg.GetType().Collate = v.Collate
}
sr.stack[len(sr.stack)-1].SetCoercibility(CoercibilityExplicit)
sr.stack[len(sr.stack)-1].SetCharsetAndCollation(arg.GetType().Charset, arg.GetType().Collate)
default:
sr.err = errors.Errorf("UnknownType: %T", v)
return retNode, false
Expand Down
1 change: 1 addition & 0 deletions planner/core/expression_rewriter.go
Original file line number Diff line number Diff line change
Expand Up @@ -1035,6 +1035,7 @@ func (er *expressionRewriter) Leave(originInNode ast.Node) (retNode ast.Node, ok
arg.GetType().Collate = v.Collate
}
er.ctxStack[len(er.ctxStack)-1].SetCoercibility(expression.CoercibilityExplicit)
er.ctxStack[len(er.ctxStack)-1].SetCharsetAndCollation(arg.GetType().Charset, arg.GetType().Collate)
default:
er.err = errors.Errorf("UnknownType: %T", v)
return retNode, false
Expand Down