Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

planner/core, expression: don't pushdown filters contains set or get var #8412

Merged
merged 5 commits into from
Nov 26, 2018
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions expression/chunk_executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,15 @@ import (
// Vectorizable checks whether a list of expressions can employ vectorized execution.
func Vectorizable(exprs []Expression) bool {
for _, expr := range exprs {
if hasUnVectorizableFunc(expr) {
if HasGetSetVarFunc(expr) {
return false
}
}
return true
}

// hasUnVectorizableFunc checks whether an expression contains functions that can not utilize the vectorized execution.
func hasUnVectorizableFunc(expr Expression) bool {
// HasGetSetVarFunc checks whether an expression contains SetVar/GetVar function.
func HasGetSetVarFunc(expr Expression) bool {
scalaFunc, ok := expr.(*ScalarFunction)
if !ok {
return false
Expand All @@ -47,7 +47,7 @@ func hasUnVectorizableFunc(expr Expression) bool {
return true
}
for _, arg := range scalaFunc.GetArgs() {
if hasUnVectorizableFunc(arg) {
if HasGetSetVarFunc(arg) {
return true
}
}
Expand Down
73 changes: 73 additions & 0 deletions expression/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3692,3 +3692,76 @@ func (s *testIntegrationSuite) TestValuesInNonInsertStmt(c *C) {
res := tk.MustQuery(`select values(a), values(b), values(c), values(d), values(e), values(f), values(g) from t;`)
res.Check(testkit.Rows(`<nil> <nil> <nil> <nil> <nil> <nil> <nil>`))
}

func (s *testIntegrationSuite) TestUserVarMockWindFunc(c *C) {
tk := testkit.NewTestKit(c, s.store)
tk.MustExec(`use test;`)
tk.MustExec(`drop table if exists t;`)
tk.MustExec(`create table t (a int, b varchar (20), c varchar (20));`)
tk.MustExec(`insert into t values
(1,'key1-value1','insert_order1'),
(1,'key1-value2','insert_order2'),
(1,'key1-value3','insert_order3'),
(1,'key1-value4','insert_order4'),
(1,'key1-value5','insert_order5'),
(1,'key1-value6','insert_order6'),
(2,'key2-value1','insert_order1'),
(2,'key2-value2','insert_order2'),
(2,'key2-value3','insert_order3'),
(2,'key2-value4','insert_order4'),
(2,'key2-value5','insert_order5'),
(2,'key2-value6','insert_order6'),
(3,'key3-value1','insert_order1'),
(3,'key3-value2','insert_order2'),
(3,'key3-value3','insert_order3'),
(3,'key3-value4','insert_order4'),
(3,'key3-value5','insert_order5'),
(3,'key3-value6','insert_order6');
`)
tk.MustExec(`SET @LAST_VAL := NULL;`)
tk.MustExec(`SET @ROW_NUM := 0;`)

tk.MustQuery(`select * from (
SELECT a,
@ROW_NUM := IF(a = @LAST_VAL, @ROW_NUM + 1, 1) AS ROW_NUM,
@LAST_VAL := a AS LAST_VAL,
b,
c
FROM (select * from t where a in (1, 2, 3) ORDER BY a, c) t1
) t2
where t2.ROW_NUM < 2;
`).Check(testkit.Rows(
`1 1 1 key1-value1 insert_order1`,
`2 1 2 key2-value1 insert_order1`,
`3 1 3 key3-value1 insert_order1`,
))

tk.MustQuery(`select * from (
SELECT a,
@ROW_NUM := IF(a = @LAST_VAL, @ROW_NUM + 1, 1) AS ROW_NUM,
@LAST_VAL := a AS LAST_VAL,
b,
c
FROM (select * from t where a in (1, 2, 3) ORDER BY a, c) t1
) t2;
`).Check(testkit.Rows(
`1 1 1 key1-value1 insert_order1`,
`1 2 1 key1-value2 insert_order2`,
`1 3 1 key1-value3 insert_order3`,
`1 4 1 key1-value4 insert_order4`,
`1 5 1 key1-value5 insert_order5`,
`1 6 1 key1-value6 insert_order6`,
`2 1 2 key2-value1 insert_order1`,
`2 2 2 key2-value2 insert_order2`,
`2 3 2 key2-value3 insert_order3`,
`2 4 2 key2-value4 insert_order4`,
`2 5 2 key2-value5 insert_order5`,
`2 6 2 key2-value6 insert_order6`,
`3 1 3 key3-value1 insert_order1`,
`3 2 3 key3-value2 insert_order2`,
`3 3 3 key3-value3 insert_order3`,
`3 4 3 key3-value4 insert_order4`,
`3 5 3 key3-value5 insert_order5`,
`3 6 3 key3-value6 insert_order6`,
))
}
30 changes: 26 additions & 4 deletions planner/core/rule_predicate_push_down.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,24 @@ func (p *baseLogicalPlan) PredicatePushDown(predicates []expression.Expression)
return nil, p.self
}

func splitSetGetVarFunc(filters []expression.Expression) ([]expression.Expression, []expression.Expression) {
canBePushDown := make([]expression.Expression, 0, len(filters))
canNotBePushDown := make([]expression.Expression, 0, len(filters))
for _, expr := range filters {
if expression.HasGetSetVarFunc(expr) {
canNotBePushDown = append(canNotBePushDown, expr)
} else {
canBePushDown = append(canBePushDown, expr)
}
}
return canBePushDown, canNotBePushDown
}

// PredicatePushDown implements LogicalPlan PredicatePushDown interface.
func (p *LogicalSelection) PredicatePushDown(predicates []expression.Expression) ([]expression.Expression, LogicalPlan) {
retConditions, child := p.children[0].PredicatePushDown(append(p.Conditions, predicates...))
canBePushDown, canNotBePushDown := splitSetGetVarFunc(p.Conditions)
retConditions, child := p.children[0].PredicatePushDown(append(canBePushDown, predicates...))
retConditions = append(retConditions, canNotBePushDown...)
if len(retConditions) > 0 {
p.Conditions = expression.PropagateConstant(p.ctx, retConditions)
// Return table dual when filter is constant false or null.
Expand Down Expand Up @@ -306,11 +321,18 @@ func isNullRejected(ctx sessionctx.Context, schema *expression.Schema, expr expr

// PredicatePushDown implements LogicalPlan PredicatePushDown interface.
func (p *LogicalProjection) PredicatePushDown(predicates []expression.Expression) (ret []expression.Expression, retPlan LogicalPlan) {
var push = make([]expression.Expression, 0, p.Schema().Len())
eurekaka marked this conversation as resolved.
Show resolved Hide resolved
canBePushed := make([]expression.Expression, 0, len(predicates))
canNotBePushed := make([]expression.Expression, 0, len(predicates))
for _, cond := range predicates {
push = append(push, expression.ColumnSubstitute(cond, p.Schema(), p.Exprs))
newFilter := expression.ColumnSubstitute(cond, p.Schema(), p.Exprs)
if !expression.HasGetSetVarFunc(newFilter) {
canBePushed = append(canBePushed, expression.ColumnSubstitute(cond, p.Schema(), p.Exprs))
} else {
canNotBePushed = append(canNotBePushed, cond)
}
}
return p.baseLogicalPlan.PredicatePushDown(push)
remained, child := p.baseLogicalPlan.PredicatePushDown(canBePushed)
return append(remained, canNotBePushed...), child
}

// PredicatePushDown implements LogicalPlan PredicatePushDown interface.
Expand Down