From 9ad0fa341ae40803a7c6c2ca9cf0e23930a4f8b2 Mon Sep 17 00:00:00 2001 From: yibin Date: Mon, 24 Jan 2022 17:06:11 +0800 Subject: [PATCH] expression: pass the arg's nullable type to target type for cast function (#31400) close pingcap/tidb#31399 --- expression/builtin_cast.go | 5 +++++ planner/core/logical_plan_test.go | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/expression/builtin_cast.go b/expression/builtin_cast.go index d10e3bb829ff0..6ee9d49ed9123 100644 --- a/expression/builtin_cast.go +++ b/expression/builtin_cast.go @@ -1848,6 +1848,11 @@ func BuildCastCollationFunction(ctx sessionctx.Context, expr Expression, ec *Exp // BuildCastFunction builds a CAST ScalarFunction from the Expression. func BuildCastFunction(ctx sessionctx.Context, expr Expression, tp *types.FieldType) (res Expression) { + argType := expr.GetType() + // If source argument's nullable, then target type should be nullable + if !mysql.HasNotNullFlag(argType.Flag) { + tp.Flag &= ^mysql.NotNullFlag + } expr = TryPushCastIntoControlFunctionForHybridType(ctx, expr, tp) var fc functionClass switch tp.EvalType() { diff --git a/planner/core/logical_plan_test.go b/planner/core/logical_plan_test.go index 0136545eff430..aec01a73e8442 100644 --- a/planner/core/logical_plan_test.go +++ b/planner/core/logical_plan_test.go @@ -110,6 +110,24 @@ func (s *testPlanSuite) TestPredicatePushDown(c *C) { } } +// Issue: 31399 +func (s *testPlanSuite) TestImplicitCastNotNullFlag(c *C) { + defer testleak.AfterTest(c)() + ctx := context.Background() + ca := "select count(*) from t3 group by a having bit_and(b) > 1;" + comment := Commentf("for %s", ca) + stmt, err := s.ParseOneStmt(ca, "", "") + c.Assert(err, IsNil, comment) + p, _, err := BuildLogicalPlanForTest(ctx, s.ctx, stmt, s.is) + c.Assert(err, IsNil) + p, err = logicalOptimize(context.TODO(), flagPredicatePushDown|flagJoinReOrder|flagPrunColumns|flagEliminateProjection, p.(LogicalPlan)) + c.Assert(err, IsNil) + // AggFuncs[0] is count; AggFuncs[1] is bit_and, args[0] is return type of the implicit cast + castNotNullFlag := (p.(*LogicalProjection).children[0].(*LogicalSelection).children[0].(*LogicalAggregation).AggFuncs[1].Args[0].GetType().Flag) & mysql.NotNullFlag + var nullableFlag uint = 0 + c.Assert(castNotNullFlag, Equals, nullableFlag) +} + func (s *testPlanSuite) TestEliminateProjectionUnderUnion(c *C) { defer testleak.AfterTest(c)() ctx := context.Background()