Skip to content

Commit e2b3132

Browse files
authored
planner: prevent pushing Projection with virtual columns down to UnionScan (#53981) (#57241)
close #53951
1 parent 23cd690 commit e2b3132

File tree

3 files changed

+62
-9
lines changed

3 files changed

+62
-9
lines changed

cmd/explaintest/r/explain_generate_column_substitute.result

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -600,15 +600,15 @@ begin;
600600
delete from t2 where c_decimal > c_double/2 order by c_int, c_str, c_double, c_decimal limit 1;
601601
desc format='brief' select t2.c_enum from t2,t1 where t1.c_int - 1 = t2.c_int - 1 order by t2.c_enum;
602602
id estRows task access object operator info
603-
Sort 12487.50 root test.t2.c_enum
604-
└─HashJoin 12487.50 root inner join, equal:[eq(minus(test.t1.c_int, 1), minus(test.t2.c_int, 1))]
605-
├─IndexReader(Build) 9990.00 root index:IndexFullScan
606-
│ └─IndexFullScan 9990.00 cop[tikv] table:t1, index:expression_index_2(`c_int` - 1) keep order:false, stats:pseudo
607-
└─Projection(Probe) 10000.00 root test.t2.c_enum, minus(test.t2.c_int, 1), test.t2._tidb_rowid
608-
└─UnionScan 8000.00 root not(isnull(minus(test.t2.c_int, 1)))
609-
└─Selection 8000.00 root not(isnull(minus(test.t2.c_int, 1)))
610-
└─TableReader 10000.00 root data:TableFullScan
611-
└─TableFullScan 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo
603+
Sort 10000.00 root test.t2.c_enum
604+
└─HashJoin 10000.00 root inner join, equal:[eq(minus(test.t1.c_int, 1), minus(test.t2.c_int, 1))]
605+
├─Selection(Build) 8000.00 root not(isnull(minus(test.t2.c_int, 1)))
606+
│ └─Projection 10000.00 root test.t2.c_enum, minus(test.t2.c_int, 1), test.t2._tidb_rowid
607+
│ └─UnionScan 10000.00 root
608+
│ └─TableReader 10000.00 root data:TableFullScan
609+
└─TableFullScan 10000.00 cop[tikv] table:t2 keep order:false, stats:pseudo
610+
└─IndexReader(Probe) 9990.00 root index:IndexFullScan
611+
└─IndexFullScan 9990.00 cop[tikv] table:t1, index:expression_index_2(`c_int` - 1) keep order:false, stats:pseudo
612612
select t2.c_enum from t2,t1 where t1.c_int - 1 = t2.c_int - 1 order by t2.c_enum;
613613
c_enum
614614
orange

executor/union_scan_test.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,54 @@ func TestUnionScanForMemBufferReader(t *testing.T) {
306306
tk.MustExec("admin check table t1;")
307307
}
308308

309+
func TestIssue53951(t *testing.T) {
310+
store := testkit.CreateMockStore(t)
311+
tk := testkit.NewTestKit(t, store)
312+
tk.MustExec("use test")
313+
tk.MustExec(`CREATE TABLE gholla_dummy1 (
314+
id varchar(10) NOT NULL,
315+
mark int,
316+
deleted_at datetime(3) NOT NULL DEFAULT '1970-01-01 01:00:01.000',
317+
account_id varchar(10) NOT NULL,
318+
metastore_id varchar(10) NOT NULL,
319+
is_deleted tinyint(1) GENERATED ALWAYS AS ((deleted_at > _utf8mb4'1970-01-01 01:00:01.000')) VIRTUAL NOT NULL,
320+
PRIMARY KEY (account_id,metastore_id,id),
321+
KEY isDeleted_accountId_metastoreId (is_deleted,account_id,metastore_id)
322+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;`)
323+
tk.MustExec(`CREATE TABLE gholla_dummy2 (
324+
id varchar(10) NOT NULL,
325+
mark int,
326+
deleted_at datetime(3) NOT NULL DEFAULT '1970-01-01 01:00:01.000',
327+
account_id varchar(10) NOT NULL,
328+
metastore_id varchar(10) NOT NULL,
329+
is_deleted tinyint(1) GENERATED ALWAYS AS ((deleted_at > _utf8mb4'1970-01-01 01:00:01.000')) VIRTUAL NOT NULL,
330+
PRIMARY KEY (account_id,metastore_id,id),
331+
KEY isDeleted_accountId_metastoreId (is_deleted,account_id,metastore_id)
332+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; `)
333+
tk.MustExec(`INSERT INTO gholla_dummy1 (id,mark,deleted_at,account_id,metastore_id) VALUES ('ABC', 1, '1970-01-01 01:00:01.000', 'ABC', 'ABC');`)
334+
tk.MustExec(`INSERT INTO gholla_dummy2 (id,mark,deleted_at,account_id,metastore_id) VALUES ('ABC', 1, '1970-01-01 01:00:01.000', 'ABC', 'ABC');`)
335+
tk.MustExec(`start transaction;`)
336+
tk.MustExec(`update gholla_dummy2 set deleted_at = NOW(), mark=2 where account_id = 'ABC' and metastore_id = 'ABC' and id = 'ABC';`)
337+
tk.MustQuery(`select
338+
/*+ INL_JOIN(g1, g2) */
339+
g1.account_id,
340+
g2.mark
341+
from
342+
gholla_dummy1 g1 FORCE INDEX(isDeleted_accountId_metastoreId)
343+
STRAIGHT_JOIN
344+
gholla_dummy2 g2 FORCE INDEX (PRIMARY)
345+
ON
346+
g1.account_id = g2.account_id AND
347+
g1.metastore_id = g2.metastore_id AND
348+
g1.id = g2.id
349+
WHERE
350+
g1.account_id = 'ABC' AND
351+
g1.metastore_id = 'ABC' AND
352+
g1.is_deleted = FALSE AND
353+
g2.is_deleted = FALSE;`).Check(testkit.Rows()) // empty result, no error
354+
tk.MustExec(`rollback`)
355+
}
356+
309357
func TestForUpdateUntouchedIndex(t *testing.T) {
310358
store := testkit.CreateMockStore(t)
311359
tk := testkit.NewTestKit(t, store)

planner/core/rule_predicate_push_down.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,11 @@ func (p *LogicalSelection) PredicatePushDown(predicates []expression.Expression,
123123

124124
// PredicatePushDown implements LogicalPlan PredicatePushDown interface.
125125
func (p *LogicalUnionScan) PredicatePushDown(predicates []expression.Expression, opt *logicalOptimizeOp) ([]expression.Expression, LogicalPlan) {
126+
if expression.ContainVirtualColumn(predicates) {
127+
// predicates with virtual columns can't be pushed down to TiKV/TiFlash so they'll be put into a Projection
128+
// below the UnionScan, but the current UnionScan doesn't support placing Projection below it, see #53951.
129+
return predicates, p
130+
}
126131
retainedPredicates, _ := p.children[0].PredicatePushDown(predicates, opt)
127132
p.conditions = make([]expression.Expression, 0, len(predicates))
128133
p.conditions = append(p.conditions, predicates...)

0 commit comments

Comments
 (0)