Skip to content

Commit

Permalink
planner: fix a panic caused by sinking a Limit with inlined Proj into…
Browse files Browse the repository at this point in the history
… IndexLookUp when accessing a partition table (#25063) (#25139)
  • Loading branch information
ti-srebot authored Jun 23, 2021
1 parent e05b97a commit 7359a15
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 15 deletions.
11 changes: 6 additions & 5 deletions cmd/explaintest/r/explain_easy.result
Original file line number Diff line number Diff line change
Expand Up @@ -124,11 +124,12 @@ Projection 10000.00 root eq(test.t1.c2, test.t2.c2)->Column#11
└─Apply 10000.00 root CARTESIAN left outer join
├─TableReader(Build) 10000.00 root data:TableFullScan
│ └─TableFullScan 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo
└─Projection(Probe) 1.00 root test.t2.c1, test.t2.c2
└─IndexLookUp 1.00 root limit embedded(offset:0, count:1)
├─Limit(Build) 1.00 cop[tikv] offset:0, count:1
│ └─IndexRangeScan 1.00 cop[tikv] table:t2, index:c1(c1) range: decided by [eq(test.t1.c1, test.t2.c1)], keep order:true, stats:pseudo
└─TableRowIDScan(Probe) 1.00 cop[tikv] table:t2 keep order:false, stats:pseudo
└─Limit(Probe) 1.00 root offset:0, count:1
└─Projection 1.00 root test.t2.c1, test.t2.c2
└─IndexLookUp 1.00 root
├─Limit(Build) 1.00 cop[tikv] offset:0, count:1
│ └─IndexRangeScan 1.00 cop[tikv] table:t2, index:c1(c1) range: decided by [eq(test.t1.c1, test.t2.c1)], keep order:true, stats:pseudo
└─TableRowIDScan(Probe) 1.00 cop[tikv] table:t2 keep order:false, stats:pseudo
explain format = 'brief' select * from t1 order by c1 desc limit 1;
id estRows task access object operator info
Limit 1.00 root offset:0, count:1
Expand Down
11 changes: 6 additions & 5 deletions cmd/explaintest/r/explain_easy_stats.result
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,12 @@ Projection 1999.00 root eq(test.t1.c2, test.t2.c2)->Column#11
└─Apply 1999.00 root CARTESIAN left outer join
├─TableReader(Build) 1999.00 root data:TableFullScan
│ └─TableFullScan 1999.00 cop[tikv] table:t1 keep order:false
└─Projection(Probe) 1.00 root test.t2.c1, test.t2.c2
└─IndexLookUp 1.00 root limit embedded(offset:0, count:1)
├─Limit(Build) 1.00 cop[tikv] offset:0, count:1
│ └─IndexRangeScan 1.25 cop[tikv] table:t2, index:c1(c1) range: decided by [eq(test.t1.c1, test.t2.c1)], keep order:true
└─TableRowIDScan(Probe) 1.00 cop[tikv] table:t2 keep order:false, stats:pseudo
└─Limit(Probe) 1.00 root offset:0, count:1
└─Projection 1.00 root test.t2.c1, test.t2.c2
└─IndexLookUp 1.00 root
├─Limit(Build) 1.00 cop[tikv] offset:0, count:1
│ └─IndexRangeScan 1.25 cop[tikv] table:t2, index:c1(c1) range: decided by [eq(test.t1.c1, test.t2.c1)], keep order:true
└─TableRowIDScan(Probe) 1.00 cop[tikv] table:t2 keep order:false, stats:pseudo
explain format = 'brief' select * from t1 order by c1 desc limit 1;
id estRows task access object operator info
Limit 1.00 root offset:0, count:1
Expand Down
36 changes: 36 additions & 0 deletions executor/partition_table_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,42 @@ func (s *partitionTableSuite) TestPartitionInfoDisable(c *C) {
tk.MustQuery("select * from t_info_null where (date = '2020-10-02' or date = '2020-10-06') and app = 'xxx' and media = '19003006'").Check(testkit.Rows())
}

func (s *partitionTableSuite) TestIssue24636(c *C) {
tk := testkit.NewTestKitWithInit(c, s.store)
tk.MustExec("create database test_issue_24636")
tk.MustExec("use test_issue_24636")

tk.MustExec(`CREATE TABLE t (a int, b date, c int, PRIMARY KEY (a,b))
PARTITION BY RANGE ( TO_DAYS(b) ) (
PARTITION p0 VALUES LESS THAN (737821),
PARTITION p1 VALUES LESS THAN (738289)
)`)
tk.MustExec(`INSERT INTO t (a, b, c) VALUES(0, '2021-05-05', 0)`)
tk.MustQuery(`select c from t use index(primary) where a=0 limit 1`).Check(testkit.Rows("0"))

tk.MustExec(`
CREATE TABLE test_partition (
a varchar(100) NOT NULL,
b date NOT NULL,
c varchar(100) NOT NULL,
d datetime DEFAULT NULL,
e datetime DEFAULT NULL,
f bigint(20) DEFAULT NULL,
g bigint(20) DEFAULT NULL,
h bigint(20) DEFAULT NULL,
i bigint(20) DEFAULT NULL,
j bigint(20) DEFAULT NULL,
k bigint(20) DEFAULT NULL,
l bigint(20) DEFAULT NULL,
PRIMARY KEY (a,b,c) /*T![clustered_index] NONCLUSTERED */
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin
PARTITION BY RANGE ( TO_DAYS(b) ) (
PARTITION pmin VALUES LESS THAN (737821),
PARTITION p20200601 VALUES LESS THAN (738289))`)
tk.MustExec(`INSERT INTO test_partition (a, b, c, d, e, f, g, h, i, j, k, l) VALUES('aaa', '2021-05-05', '428ff6a1-bb37-42ac-9883-33d7a29961e6', '2021-05-06 08:13:38', '2021-05-06 13:28:08', 0, 8, 3, 0, 9, 1, 0)`)
tk.MustQuery(`select c,j,l from test_partition where c='428ff6a1-bb37-42ac-9883-33d7a29961e6' and a='aaa' limit 0, 200`).Check(testkit.Rows("428ff6a1-bb37-42ac-9883-33d7a29961e6 9 0"))
}

func (s *globalIndexSuite) TestGlobalIndexScan(c *C) {
tk := testkit.NewTestKitWithInit(c, s.store)
tk.MustExec("drop table if exists p")
Expand Down
1 change: 1 addition & 0 deletions planner/core/exhaust_physical_plans.go
Original file line number Diff line number Diff line change
Expand Up @@ -2037,6 +2037,7 @@ func (lt *LogicalTopN) getPhysLimits(prop *property.PhysicalProperty) []Physical
Count: lt.Count,
Offset: lt.Offset,
}.Init(lt.ctx, lt.stats, lt.blockOffset, resultProp)
limit.SetSchema(lt.Schema())
ret = append(ret, limit)
}
return ret
Expand Down
10 changes: 10 additions & 0 deletions planner/core/task.go
Original file line number Diff line number Diff line change
Expand Up @@ -1104,6 +1104,16 @@ func (p *PhysicalLimit) sinkIntoIndexLookUp(t task) bool {
return false
}
}

// If this happens, some Projection Operator must be inlined into this Limit. (issues/14428)
// For example, if the original plan is `IndexLookUp(col1, col2) -> Limit(col1, col2) -> Project(col1)`,
// then after inlining the Project, it will be `IndexLookUp(col1, col2) -> Limit(col1)` here.
// If the Limit is sunk into the IndexLookUp, the IndexLookUp's schema needs to be updated as well,
// but updating it here is not safe, so do not sink Limit into this IndexLookUp in this case now.
if p.Schema().Len() != reader.Schema().Len() {
return false
}

// We can sink Limit into IndexLookUpReader only if tablePlan contains no Selection.
ts, isTableScan := reader.tablePlan.(*PhysicalTableScan)
if !isTableScan {
Expand Down
11 changes: 6 additions & 5 deletions planner/core/testdata/integration_suite_out.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@
{
"SQL": "explain format = 'brief' select * from tbl use index(idx_b_c) where b > 1 order by b desc limit 2,1",
"Plan": [
"Projection 1.00 root test.tbl.a, test.tbl.b, test.tbl.c",
"└─IndexLookUp 1.00 root limit embedded(offset:2, count:1)",
" ├─Limit(Build) 3.00 cop[tikv] offset:0, count:3",
" │ └─IndexRangeScan 3.00 cop[tikv] table:tbl, index:idx_b_c(b, c) range:(1,+inf], keep order:true, desc",
" └─TableRowIDScan(Probe) 1.00 cop[tikv] table:tbl keep order:false, stats:pseudo"
"Limit 1.00 root offset:2, count:1",
"└─Projection 3.00 root test.tbl.a, test.tbl.b, test.tbl.c",
" └─IndexLookUp 3.00 root ",
" ├─Limit(Build) 3.00 cop[tikv] offset:0, count:3",
" │ └─IndexRangeScan 3.00 cop[tikv] table:tbl, index:idx_b_c(b, c) range:(1,+inf], keep order:true, desc",
" └─TableRowIDScan(Probe) 3.00 cop[tikv] table:tbl keep order:false, stats:pseudo"
]
},
{
Expand Down

0 comments on commit 7359a15

Please sign in to comment.