Skip to content

Commit

Permalink
cherry pick pingcap#19620 to release-3.0
Browse files Browse the repository at this point in the history
Signed-off-by: ti-srebot <ti-srebot@pingcap.com>
  • Loading branch information
eurekaka authored and ti-srebot committed Nov 12, 2020
1 parent 6cf4e32 commit b4e4c8a
Show file tree
Hide file tree
Showing 9 changed files with 285 additions and 18 deletions.
34 changes: 34 additions & 0 deletions cmd/explaintest/r/explain_easy.result
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ StreamAgg_12 1.00 root funcs:sum(col_0)
└─IndexReader_17 10000.00 root index:IndexScan_16
└─IndexScan_16 10000.00 cop table:t2, index:c1, range:[NULL,+inf], keep order:false, stats:pseudo
explain select 1 in (select c2 from t2) from t1;
<<<<<<< HEAD
id count task operator info
Projection_6 10000.00 root 5_aux_0
└─HashLeftJoin_7 10000.00 root CARTESIAN left outer semi join, inner:TableReader_12
Expand All @@ -251,6 +252,23 @@ StreamAgg_12 1.00 root funcs:sum(col_0)
└─TableReader_18 10.00 root data:Selection_17
└─Selection_17 10.00 cop eq(6, test.t2.c2)
└─TableScan_16 10000.00 cop table:t2, range:[-inf,+inf], keep order:false, stats:pseudo
=======
id estRows task access object operator info
HashJoin_7 10000.00 root CARTESIAN left outer semi join, other cond:eq(1, test.t2.c2)
├─TableReader_13(Build) 10000.00 root data:TableFullScan_12
│ └─TableFullScan_12 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo
└─TableReader_9(Probe) 10000.00 root data:TableFullScan_8
└─TableFullScan_8 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo
explain select sum(6 in (select c2 from t2)) from t1;
id estRows task access object operator info
StreamAgg_12 1.00 root funcs:sum(Column#10)->Column#8
└─Projection_21 10000.00 root cast(Column#7, decimal(65,0) BINARY)->Column#10
└─HashJoin_20 10000.00 root CARTESIAN left outer semi join, other cond:eq(6, test.t2.c2)
├─TableReader_19(Build) 10000.00 root data:TableFullScan_18
│ └─TableFullScan_18 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo
└─TableReader_15(Probe) 10000.00 root data:TableFullScan_14
└─TableFullScan_14 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo
>>>>>>> 3ef3e54b5... planner: don't push down null sensitive join conditions (#19620)
explain format="dot" select sum(t1.c1 in (select c1 from t2)) from t1;
dot contents

Expand Down Expand Up @@ -288,16 +306,22 @@ subgraph cluster6{
node [style=filled, color=lightgrey]
color=black
label = "root"
<<<<<<< HEAD
"Projection_6" -> "HashLeftJoin_7"
"HashLeftJoin_7" -> "IndexReader_9"
"HashLeftJoin_7" -> "TableReader_12"
=======
"HashJoin_7" -> "TableReader_9"
"HashJoin_7" -> "TableReader_13"
>>>>>>> 3ef3e54b5... planner: don't push down null sensitive join conditions (#19620)
}
subgraph cluster8{
node [style=filled, color=lightgrey]
color=black
label = "cop"
"IndexScan_8"
}
<<<<<<< HEAD
subgraph cluster11{
node [style=filled, color=lightgrey]
color=black
Expand All @@ -306,6 +330,16 @@ label = "cop"
}
"IndexReader_9" -> "IndexScan_8"
"TableReader_12" -> "Selection_11"
=======
subgraph cluster12{
node [style=filled, color=lightgrey]
color=black
label = "cop"
"TableFullScan_12"
}
"TableReader_9" -> "TableFullScan_8"
"TableReader_13" -> "TableFullScan_12"
>>>>>>> 3ef3e54b5... planner: don't push down null sensitive join conditions (#19620)
}

drop table if exists t1, t2, t3, t4;
Expand Down
25 changes: 25 additions & 0 deletions cmd/explaintest/r/explain_easy_stats.result
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ Limit_10 1.00 root offset:0, count:1
└─TableScan_18 1.00 cop table:t1, range:[-inf,+inf], keep order:true, desc
set @@session.tidb_opt_insubq_to_join_and_agg=0;
explain select 1 in (select c2 from t2) from t1;
<<<<<<< HEAD
id count task operator info
Projection_6 1999.00 root 5_aux_0
└─HashLeftJoin_7 1999.00 root CARTESIAN left outer semi join, inner:TableReader_12
Expand All @@ -134,6 +135,14 @@ Projection_6 1999.00 root 5_aux_0
└─TableReader_12 0.00 root data:Selection_11
└─Selection_11 0.00 cop eq(1, test.t2.c2)
└─TableScan_10 1985.00 cop table:t2, range:[-inf,+inf], keep order:false
=======
id estRows task access object operator info
HashJoin_7 1999.00 root CARTESIAN left outer semi join, other cond:eq(1, test.t2.c2)
├─TableReader_13(Build) 1985.00 root data:TableFullScan_12
│ └─TableFullScan_12 1985.00 cop[tikv] table:t2 keep order:false
└─TableReader_9(Probe) 1999.00 root data:TableFullScan_8
└─TableFullScan_8 1999.00 cop[tikv] table:t1 keep order:false
>>>>>>> 3ef3e54b5... planner: don't push down null sensitive join conditions (#19620)
explain format="dot" select 1 in (select c2 from t2) from t1;
dot contents

Expand All @@ -142,16 +151,22 @@ subgraph cluster6{
node [style=filled, color=lightgrey]
color=black
label = "root"
<<<<<<< HEAD
"Projection_6" -> "HashLeftJoin_7"
"HashLeftJoin_7" -> "IndexReader_9"
"HashLeftJoin_7" -> "TableReader_12"
=======
"HashJoin_7" -> "TableReader_9"
"HashJoin_7" -> "TableReader_13"
>>>>>>> 3ef3e54b5... planner: don't push down null sensitive join conditions (#19620)
}
subgraph cluster8{
node [style=filled, color=lightgrey]
color=black
label = "cop"
"IndexScan_8"
}
<<<<<<< HEAD
subgraph cluster11{
node [style=filled, color=lightgrey]
color=black
Expand All @@ -160,6 +175,16 @@ label = "cop"
}
"IndexReader_9" -> "IndexScan_8"
"TableReader_12" -> "Selection_11"
=======
subgraph cluster12{
node [style=filled, color=lightgrey]
color=black
label = "cop"
"TableFullScan_12"
}
"TableReader_9" -> "TableFullScan_8"
"TableReader_13" -> "TableFullScan_12"
>>>>>>> 3ef3e54b5... planner: don't push down null sensitive join conditions (#19620)
}

explain select * from index_prune WHERE a = 1010010404050976781 AND b = 26467085526790 LIMIT 1;
Expand Down
26 changes: 26 additions & 0 deletions executor/executor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2096,6 +2096,32 @@ func (s *testSuite) TestRow(c *C) {
result.Check(testkit.Rows("0"))
result = tk.MustQuery("select (select 1)")
result.Check(testkit.Rows("1"))

tk.MustExec("drop table if exists t1")
tk.MustExec("create table t1 (a int, b int)")
tk.MustExec("insert t1 values (1,2),(1,null)")
tk.MustExec("drop table if exists t2")
tk.MustExec("create table t2 (c int, d int)")
tk.MustExec("insert t2 values (0,0)")

tk.MustQuery("select * from t2 where (1,2) in (select * from t1)").Check(testkit.Rows("0 0"))
tk.MustQuery("select * from t2 where (1,2) not in (select * from t1)").Check(testkit.Rows())
tk.MustQuery("select * from t2 where (1,1) not in (select * from t1)").Check(testkit.Rows())
tk.MustQuery("select * from t2 where (1,null) in (select * from t1)").Check(testkit.Rows())
tk.MustQuery("select * from t2 where (null,null) in (select * from t1)").Check(testkit.Rows())

tk.MustExec("delete from t1 where a=1 and b=2")
tk.MustQuery("select (1,1) in (select * from t2) from t1").Check(testkit.Rows("0"))
tk.MustQuery("select (1,1) not in (select * from t2) from t1").Check(testkit.Rows("1"))
tk.MustQuery("select (1,1) in (select 1,1 from t2) from t1").Check(testkit.Rows("1"))
tk.MustQuery("select (1,1) not in (select 1,1 from t2) from t1").Check(testkit.Rows("0"))

// MySQL 5.7 returns 1 for these 2 queries, which is wrong.
tk.MustQuery("select (1,null) not in (select 1,1 from t2) from t1").Check(testkit.Rows("<nil>"))
tk.MustQuery("select (t1.a,null) not in (select 1,1 from t2) from t1").Check(testkit.Rows("<nil>"))

tk.MustQuery("select (1,null) in (select * from t1)").Check(testkit.Rows("<nil>"))
tk.MustQuery("select (1,null) not in (select * from t1)").Check(testkit.Rows("<nil>"))
}

func (s *testSuite) TestColumnName(c *C) {
Expand Down
59 changes: 59 additions & 0 deletions executor/join_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -677,6 +677,65 @@ func (s *testSuite2) TestSubquery(c *C) {
tk.MustExec("insert into t2 values(1)")
tk.MustQuery("select * from t1 where a in (select a from t2)").Check(testkit.Rows("1"))

tk.MustExec("insert into t2 value(null)")
tk.MustQuery("select * from t1 where 1 in (select b from t2)").Check(testkit.Rows("1"))
tk.MustQuery("select * from t1 where 1 not in (select b from t2)").Check(testkit.Rows())
tk.MustQuery("select * from t1 where 2 not in (select b from t2)").Check(testkit.Rows())
tk.MustQuery("select * from t1 where 2 in (select b from t2)").Check(testkit.Rows())
tk.MustQuery("select 1 in (select b from t2) from t1").Check(testkit.Rows("1"))
tk.MustQuery("select 1 in (select 1 from t2) from t1").Check(testkit.Rows("1"))
tk.MustQuery("select 1 not in (select b from t2) from t1").Check(testkit.Rows("0"))
tk.MustQuery("select 1 not in (select 1 from t2) from t1").Check(testkit.Rows("0"))

tk.MustExec("delete from t2 where b=1")
tk.MustQuery("select 1 in (select b from t2) from t1").Check(testkit.Rows("<nil>"))
tk.MustQuery("select 1 not in (select b from t2) from t1").Check(testkit.Rows("<nil>"))
tk.MustQuery("select 1 not in (select 1 from t2) from t1").Check(testkit.Rows("0"))
tk.MustQuery("select 1 in (select 1 from t2) from t1").Check(testkit.Rows("1"))
tk.MustQuery("select 1 not in (select null from t1) from t2").Check(testkit.Rows("<nil>"))
tk.MustQuery("select 1 in (select null from t1) from t2").Check(testkit.Rows("<nil>"))

tk.MustExec("drop table if exists s")
tk.MustExec("create table s(a int not null, b int)")
tk.MustExec("set sql_mode = ''")
tk.MustQuery("select (2,0) in (select s.a, min(s.b) from s) as f").Check(testkit.Rows("<nil>"))
tk.MustQuery("select (2,0) not in (select s.a, min(s.b) from s) as f").Check(testkit.Rows("<nil>"))
tk.MustQuery("select (2,0) = any (select s.a, min(s.b) from s) as f").Check(testkit.Rows("<nil>"))
tk.MustQuery("select (2,0) != all (select s.a, min(s.b) from s) as f").Check(testkit.Rows("<nil>"))
tk.MustQuery("select (2,0) in (select s.b, min(s.b) from s) as f").Check(testkit.Rows("<nil>"))
tk.MustQuery("select (2,0) not in (select s.b, min(s.b) from s) as f").Check(testkit.Rows("<nil>"))
tk.MustQuery("select (2,0) = any (select s.b, min(s.b) from s) as f").Check(testkit.Rows("<nil>"))
tk.MustQuery("select (2,0) != all (select s.b, min(s.b) from s) as f").Check(testkit.Rows("<nil>"))
tk.MustExec("insert into s values(1,null)")
tk.MustQuery("select 1 in (select b from s)").Check(testkit.Rows("<nil>"))

tk.MustExec("drop table if exists t")
tk.MustExec("create table t(a int)")
tk.MustExec("insert into t values(1),(null)")
tk.MustQuery("select a not in (select 1) from t").Sort().Check(testkit.Rows(
"0",
"<nil>",
))
tk.MustQuery("select 1 not in (select null from t t1) from t").Check(testkit.Rows(
"<nil>",
"<nil>",
))
tk.MustQuery("select 1 in (select null from t t1) from t").Check(testkit.Rows(
"<nil>",
"<nil>",
))
tk.MustQuery("select a in (select 0) xx from (select null as a) x").Check(testkit.Rows("<nil>"))

tk.MustExec("drop table t")
tk.MustExec("create table t(a int, b int)")
tk.MustExec("insert into t values(1,null),(null, null),(null, 2)")
tk.MustQuery("select * from t t1 where (2 in (select a from t t2 where (t2.b=t1.b) is null))").Check(testkit.Rows())
tk.MustQuery("select (t2.a in (select t1.a from t t1)) is true from t t2").Sort().Check(testkit.Rows(
"0",
"0",
"1",
))

tk.MustExec("set @@tidb_hash_join_concurrency=5")
}

Expand Down
11 changes: 0 additions & 11 deletions expression/aggregation/base_func_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,3 @@ 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)
}
41 changes: 41 additions & 0 deletions expression/aggregation/descriptor.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"math"
"strconv"

"github.com/pingcap/errors"
"github.com/pingcap/parser/ast"
"github.com/pingcap/parser/model"
"github.com/pingcap/parser/mysql"
Expand Down Expand Up @@ -251,3 +252,43 @@ func (a *AggFuncDesc) evalNullValueInOuterJoin4BitOr(ctx sessionctx.Context, sch
}
return con.Value, true
}

// UpdateNotNullFlag4RetType checks if we should remove the NotNull flag for the return type of the agg.
func (a *AggFuncDesc) UpdateNotNullFlag4RetType(hasGroupBy, allAggsFirstRow bool) error {
var removeNotNull bool
switch a.Name {
case ast.AggFuncCount, ast.AggFuncApproxCountDistinct, ast.AggFuncApproxPercentile,
ast.AggFuncBitAnd, ast.AggFuncBitOr, ast.AggFuncBitXor,
ast.WindowFuncFirstValue, ast.WindowFuncLastValue, ast.WindowFuncNthValue, ast.WindowFuncRowNumber,
ast.WindowFuncRank, ast.WindowFuncDenseRank, ast.WindowFuncCumeDist, ast.WindowFuncNtile, ast.WindowFuncPercentRank,
ast.WindowFuncLead, ast.WindowFuncLag, ast.AggFuncJsonObjectAgg,
ast.AggFuncVarSamp, ast.AggFuncVarPop, ast.AggFuncStddevPop, ast.AggFuncStddevSamp:
removeNotNull = false
case ast.AggFuncSum, ast.AggFuncAvg, ast.AggFuncGroupConcat:
if !hasGroupBy {
removeNotNull = true
}
// `select max(a) from empty_tbl` returns `null`, while `select max(a) from empty_tbl group by b` returns empty.
case ast.AggFuncMax, ast.AggFuncMin:
if !hasGroupBy && a.RetTp.Tp != mysql.TypeBit {
removeNotNull = true
}
// `select distinct a from empty_tbl` returns empty
// `select a from empty_tbl group by b` returns empty
// `select a, max(a) from empty_tbl` returns `(null, null)`
// `select a, max(a) from empty_tbl group by b` returns empty
// `select a, count(a) from empty_tbl` returns `(null, 0)`
// `select a, count(a) from empty_tbl group by b` returns empty
case ast.AggFuncFirstRow:
if !allAggsFirstRow && !hasGroupBy {
removeNotNull = true
}
default:
return errors.Errorf("unsupported agg function: %s", a.Name)
}
if removeNotNull {
a.RetTp = a.RetTp.Clone()
a.RetTp.Flag &^= mysql.NotNullFlag
}
return nil
}
24 changes: 24 additions & 0 deletions expression/expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,30 @@ func IsEQCondFromIn(expr Expression) bool {
return len(cols) > 0
}

<<<<<<< HEAD
=======
// ExprNotNull checks if an expression is possible to be null.
func ExprNotNull(expr Expression) bool {
if c, ok := expr.(*Constant); ok {
return !c.Value.IsNull()
}
// For ScalarFunction, the result would not be correct until we support maintaining
// NotNull flag for it.
return mysql.HasNotNullFlag(expr.GetType().Flag)
}

// HandleOverflowOnSelection handles Overflow errors when evaluating selection filters.
// We should ignore overflow errors when evaluating selection conditions:
// INSERT INTO t VALUES ("999999999999999999");
// SELECT * FROM t WHERE v;
func HandleOverflowOnSelection(sc *stmtctx.StatementContext, val int64, err error) (int64, error) {
if sc.InSelectStmt && err != nil && types.ErrOverflow.Equal(err) {
return -1, nil
}
return val, err
}

>>>>>>> 3ef3e54b5... planner: don't push down null sensitive join conditions (#19620)
// EvalBool evaluates expression list to a boolean value. The first returned value
// indicates bool result of the expression list, the second returned value indicates
// whether the result of the expression list is null, it can only be true when the
Expand Down
Loading

0 comments on commit b4e4c8a

Please sign in to comment.