From 00801a741ce1d7a921a19d32dae6991cbf71b1c0 Mon Sep 17 00:00:00 2001 From: SunRunAway Date: Thu, 8 Aug 2019 17:13:58 +0800 Subject: [PATCH] expression: remove the NotNullFlag for aggregation func MAX/MIN when inferring type (#11343) (#11641) --- cmd/explaintest/r/tpch.result | 65 ++++++++++++------------ expression/aggregation/base_func.go | 4 ++ expression/aggregation/base_func_test.go | 11 ++++ expression/integration_test.go | 5 ++ 4 files changed, 53 insertions(+), 32 deletions(-) diff --git a/cmd/explaintest/r/tpch.result b/cmd/explaintest/r/tpch.result index eefcc37ffaf98..45f0cdc023f06 100644 --- a/cmd/explaintest/r/tpch.result +++ b/cmd/explaintest/r/tpch.result @@ -182,38 +182,39 @@ s_name, p_partkey limit 100; id count task operator info -Projection_36 100.00 root tpch.supplier.s_acctbal, tpch.supplier.s_name, tpch.nation.n_name, tpch.part.p_partkey, tpch.part.p_mfgr, tpch.supplier.s_address, tpch.supplier.s_phone, tpch.supplier.s_comment -└─TopN_39 100.00 root tpch.supplier.s_acctbal:desc, tpch.nation.n_name:asc, tpch.supplier.s_name:asc, tpch.part.p_partkey:asc, offset:0, count:100 - └─HashRightJoin_44 155496.00 root inner join, inner:HashLeftJoin_50, equal:[eq(tpch.part.p_partkey, tpch.partsupp.ps_partkey) eq(tpch.partsupp.ps_supplycost, min(ps_supplycost))] - ├─HashLeftJoin_50 155496.00 root inner join, inner:TableReader_73, equal:[eq(tpch.partsupp.ps_partkey, tpch.part.p_partkey)] - │ ├─HashRightJoin_53 8155010.44 root inner join, inner:HashRightJoin_55, equal:[eq(tpch.supplier.s_suppkey, tpch.partsupp.ps_suppkey)] - │ │ ├─HashRightJoin_55 100000.00 root inner join, inner:HashRightJoin_61, equal:[eq(tpch.nation.n_nationkey, tpch.supplier.s_nationkey)] - │ │ │ ├─HashRightJoin_61 5.00 root inner join, inner:TableReader_66, equal:[eq(tpch.region.r_regionkey, tpch.nation.n_regionkey)] - │ │ │ │ ├─TableReader_66 1.00 root data:Selection_65 - │ │ │ │ │ └─Selection_65 1.00 cop eq(tpch.region.r_name, "ASIA") - │ │ │ │ │ └─TableScan_64 5.00 cop table:region, range:[-inf,+inf], keep order:false - │ │ │ │ └─TableReader_63 25.00 root data:TableScan_62 - │ │ │ │ └─TableScan_62 25.00 cop table:nation, range:[-inf,+inf], keep order:false - │ │ │ └─TableReader_68 500000.00 root data:TableScan_67 - │ │ │ └─TableScan_67 500000.00 cop table:supplier, range:[-inf,+inf], keep order:false - │ │ └─TableReader_70 40000000.00 root data:TableScan_69 - │ │ └─TableScan_69 40000000.00 cop table:partsupp, range:[-inf,+inf], keep order:false - │ └─TableReader_73 155496.00 root data:Selection_72 - │ └─Selection_72 155496.00 cop eq(tpch.part.p_size, 30), like(tpch.part.p_type, "%STEEL", 92) - │ └─TableScan_71 10000000.00 cop table:part, range:[-inf,+inf], keep order:false - └─HashAgg_76 8155010.44 root group by:tpch.partsupp.ps_partkey, funcs:min(tpch.partsupp.ps_supplycost), firstrow(tpch.partsupp.ps_partkey) - └─HashRightJoin_80 8155010.44 root inner join, inner:HashRightJoin_82, equal:[eq(tpch.supplier.s_suppkey, tpch.partsupp.ps_suppkey)] - ├─HashRightJoin_82 100000.00 root inner join, inner:HashRightJoin_88, equal:[eq(tpch.nation.n_nationkey, tpch.supplier.s_nationkey)] - │ ├─HashRightJoin_88 5.00 root inner join, inner:TableReader_93, equal:[eq(tpch.region.r_regionkey, tpch.nation.n_regionkey)] - │ │ ├─TableReader_93 1.00 root data:Selection_92 - │ │ │ └─Selection_92 1.00 cop eq(tpch.region.r_name, "ASIA") - │ │ │ └─TableScan_91 5.00 cop table:region, range:[-inf,+inf], keep order:false - │ │ └─TableReader_90 25.00 root data:TableScan_89 - │ │ └─TableScan_89 25.00 cop table:nation, range:[-inf,+inf], keep order:false - │ └─TableReader_95 500000.00 root data:TableScan_94 - │ └─TableScan_94 500000.00 cop table:supplier, range:[-inf,+inf], keep order:false - └─TableReader_97 40000000.00 root data:TableScan_96 - └─TableScan_96 40000000.00 cop table:partsupp, range:[-inf,+inf], keep order:false +Projection_37 100.00 root tpch.supplier.s_acctbal, tpch.supplier.s_name, tpch.nation.n_name, tpch.part.p_partkey, tpch.part.p_mfgr, tpch.supplier.s_address, tpch.supplier.s_phone, tpch.supplier.s_comment +└─TopN_40 100.00 root tpch.supplier.s_acctbal:desc, tpch.nation.n_name:asc, tpch.supplier.s_name:asc, tpch.part.p_partkey:asc, offset:0, count:100 + └─HashRightJoin_45 155496.00 root inner join, inner:HashLeftJoin_51, equal:[eq(tpch.part.p_partkey, tpch.partsupp.ps_partkey) eq(tpch.partsupp.ps_supplycost, min(ps_supplycost))] + ├─HashLeftJoin_51 155496.00 root inner join, inner:TableReader_74, equal:[eq(tpch.partsupp.ps_partkey, tpch.part.p_partkey)] + │ ├─HashRightJoin_54 8155010.44 root inner join, inner:HashRightJoin_56, equal:[eq(tpch.supplier.s_suppkey, tpch.partsupp.ps_suppkey)] + │ │ ├─HashRightJoin_56 100000.00 root inner join, inner:HashRightJoin_62, equal:[eq(tpch.nation.n_nationkey, tpch.supplier.s_nationkey)] + │ │ │ ├─HashRightJoin_62 5.00 root inner join, inner:TableReader_67, equal:[eq(tpch.region.r_regionkey, tpch.nation.n_regionkey)] + │ │ │ │ ├─TableReader_67 1.00 root data:Selection_66 + │ │ │ │ │ └─Selection_66 1.00 cop eq(tpch.region.r_name, "ASIA") + │ │ │ │ │ └─TableScan_65 5.00 cop table:region, range:[-inf,+inf], keep order:false + │ │ │ │ └─TableReader_64 25.00 root data:TableScan_63 + │ │ │ │ └─TableScan_63 25.00 cop table:nation, range:[-inf,+inf], keep order:false + │ │ │ └─TableReader_69 500000.00 root data:TableScan_68 + │ │ │ └─TableScan_68 500000.00 cop table:supplier, range:[-inf,+inf], keep order:false + │ │ └─TableReader_71 40000000.00 root data:TableScan_70 + │ │ └─TableScan_70 40000000.00 cop table:partsupp, range:[-inf,+inf], keep order:false + │ └─TableReader_74 155496.00 root data:Selection_73 + │ └─Selection_73 155496.00 cop eq(tpch.part.p_size, 30), like(tpch.part.p_type, "%STEEL", 92) + │ └─TableScan_72 10000000.00 cop table:part, range:[-inf,+inf], keep order:false + └─Selection_75 6524008.35 root not(isnull(min(ps_supplycost))) + └─HashAgg_78 8155010.44 root group by:tpch.partsupp.ps_partkey, funcs:min(tpch.partsupp.ps_supplycost), firstrow(tpch.partsupp.ps_partkey) + └─HashRightJoin_82 8155010.44 root inner join, inner:HashRightJoin_84, equal:[eq(tpch.supplier.s_suppkey, tpch.partsupp.ps_suppkey)] + ├─HashRightJoin_84 100000.00 root inner join, inner:HashRightJoin_90, equal:[eq(tpch.nation.n_nationkey, tpch.supplier.s_nationkey)] + │ ├─HashRightJoin_90 5.00 root inner join, inner:TableReader_95, equal:[eq(tpch.region.r_regionkey, tpch.nation.n_regionkey)] + │ │ ├─TableReader_95 1.00 root data:Selection_94 + │ │ │ └─Selection_94 1.00 cop eq(tpch.region.r_name, "ASIA") + │ │ │ └─TableScan_93 5.00 cop table:region, range:[-inf,+inf], keep order:false + │ │ └─TableReader_92 25.00 root data:TableScan_91 + │ │ └─TableScan_91 25.00 cop table:nation, range:[-inf,+inf], keep order:false + │ └─TableReader_97 500000.00 root data:TableScan_96 + │ └─TableScan_96 500000.00 cop table:supplier, range:[-inf,+inf], keep order:false + └─TableReader_99 40000000.00 root data:TableScan_98 + └─TableScan_98 40000000.00 cop table:partsupp, range:[-inf,+inf], keep order:false /* Q3 Shipping Priority Query This query retrieves the 10 unshipped orders with the highest value. diff --git a/expression/aggregation/base_func.go b/expression/aggregation/base_func.go index 1a4a971c02294..6706eeea99d9d 100644 --- a/expression/aggregation/base_func.go +++ b/expression/aggregation/base_func.go @@ -184,6 +184,10 @@ func (a *baseFuncDesc) typeInfer4MaxMin(ctx sessionctx.Context) { a.Args[0] = expression.BuildCastFunction(ctx, a.Args[0], tp) } a.RetTp = a.Args[0].GetType() + if (a.Name == ast.AggFuncMax || a.Name == ast.AggFuncMin) && a.RetTp.Tp != mysql.TypeBit { + a.RetTp = a.Args[0].GetType().Clone() + a.RetTp.Flag &^= mysql.NotNullFlag + } if a.RetTp.Tp == mysql.TypeEnum || a.RetTp.Tp == mysql.TypeSet { a.RetTp = &types.FieldType{Tp: mysql.TypeString, Flen: mysql.MaxFieldCharLength} } diff --git a/expression/aggregation/base_func_test.go b/expression/aggregation/base_func_test.go index ba7fd757fdbaa..bf6e96364fe39 100644 --- a/expression/aggregation/base_func_test.go +++ b/expression/aggregation/base_func_test.go @@ -39,3 +39,14 @@ func (s *testBaseFuncSuite) TestClone(c *check.C) { c.Assert(desc.Args[0], check.Equals, col) c.Assert(desc.equal(s.ctx, cloned), check.IsFalse) } + +func (s *testBaseFuncSuite) TestMaxMin(c *check.C) { + col := &expression.Column{ + UniqueID: 0, + RetType: types.NewFieldType(mysql.TypeLonglong), + } + col.RetType.Flag |= mysql.NotNullFlag + desc, err := newBaseFuncDesc(s.ctx, ast.AggFuncMax, []expression.Expression{col}) + c.Assert(err, check.IsNil) + c.Assert(mysql.HasNotNullFlag(desc.RetTp.Flag), check.IsFalse) +} diff --git a/expression/integration_test.go b/expression/integration_test.go index 7fbaaa7494b51..5383834799e75 100644 --- a/expression/integration_test.go +++ b/expression/integration_test.go @@ -2760,6 +2760,11 @@ func (s *testIntegrationSuite) TestControlBuiltin(c *C) { result = tk.MustQuery("select ifnull(null, null)") result.Check(testkit.Rows("")) + tk.MustExec("drop table if exists t1") + tk.MustExec("create table t1(a bigint not null)") + result = tk.MustQuery("select ifnull(max(a),0) from t1") + result.Check(testkit.Rows("0")) + tk.MustExec("drop table if exists t1") tk.MustExec("drop table if exists t2") tk.MustExec("create table t1(a decimal(20,4))")