Skip to content

Commit

Permalink
plan: support subquery in Do statement (#8343) (#9877)
Browse files Browse the repository at this point in the history
  • Loading branch information
eurekaka authored and zz-jason committed Mar 25, 2019
1 parent f9c995a commit 705341b
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 11 deletions.
13 changes: 13 additions & 0 deletions executor/executor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3435,3 +3435,16 @@ func (s *testSuite) TestRowID(c *C) {
tk.MustExec(`insert into t values('a')`)
tk.MustQuery("select *, _tidb_rowid from t use index(`primary`) where _tidb_rowid=1").Check(testkit.Rows("a 1"))
}

func (s *testSuite) TestDoSubquery(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)`)
_, err := tk.Exec(`do 1 in (select * from t)`)
c.Assert(err, IsNil, Commentf("err %v", err))
tk.MustExec(`insert into t values(1)`)
r, err := tk.Exec(`do 1 in (select * from t)`)
c.Assert(err, IsNil, Commentf("err %v", err))
c.Assert(r, IsNil, Commentf("result of Do not empty"))
}
31 changes: 31 additions & 0 deletions planner/core/physical_plan_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1303,3 +1303,34 @@ func (s *testPlanSuite) TestIndexLookupCartesianJoin(c *C) {
lastWarn := warnings[len(warnings)-1]
c.Assert(lastWarn.Err.Error(), Equals, "[planner:1815]Optimizer Hint /*+ TIDB_INLJ(t1, t2) */ is inapplicable without column equal ON condition")
}

func (s *testPlanSuite) TestDoSubquery(c *C) {
defer testleak.AfterTest(c)()
store, dom, err := newStoreWithBootstrap()
c.Assert(err, IsNil)
defer func() {
dom.Close()
store.Close()
}()
se, err := session.CreateSession4Test(store)
c.Assert(err, IsNil)
_, err = se.Execute(context.Background(), "use test")
c.Assert(err, IsNil)
tests := []struct {
sql string
best string
}{
{
sql: "do 1 in (select a from t)",
best: "LeftHashJoin{Dual->TableReader(Table(t))}->Projection",
},
}
for _, tt := range tests {
comment := Commentf("for %s", tt.sql)
stmt, err := s.ParseOneStmt(tt.sql, "", "")
c.Assert(err, IsNil, comment)
p, err := core.Optimize(se, stmt, s.is)
c.Assert(err, IsNil)
c.Assert(core.ToString(p), Equals, tt.best, comment)
}
}
21 changes: 12 additions & 9 deletions planner/core/planbuilder.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,26 +210,29 @@ func (b *planBuilder) buildExecute(v *ast.ExecuteStmt) (Plan, error) {
}

func (b *planBuilder) buildDo(v *ast.DoStmt) (Plan, error) {
var p LogicalPlan
dual := LogicalTableDual{RowCount: 1}.init(b.ctx)

p := LogicalProjection{Exprs: make([]expression.Expression, 0, len(v.Exprs))}.init(b.ctx)
dual.SetSchema(expression.NewSchema())
p = dual
proj := LogicalProjection{Exprs: make([]expression.Expression, 0, len(v.Exprs))}.init(b.ctx)
schema := expression.NewSchema(make([]*expression.Column, 0, len(v.Exprs))...)
for _, astExpr := range v.Exprs {
expr, _, err := b.rewrite(astExpr, dual, nil, true)
expr, np, err := b.rewrite(astExpr, p, nil, true)
if err != nil {
return nil, errors.Trace(err)
}
p.Exprs = append(p.Exprs, expr)
p = np
proj.Exprs = append(proj.Exprs, expr)
schema.Append(&expression.Column{
UniqueID: b.ctx.GetSessionVars().AllocPlanColumnID(),
RetType: expr.GetType(),
})
}
p.SetChildren(dual)
p.self = p
p.SetSchema(schema)
p.calculateNoDelay = true
return p, nil
proj.SetChildren(p)
proj.self = proj
proj.SetSchema(schema)
proj.calculateNoDelay = true
return proj, nil
}

func (b *planBuilder) buildSet(v *ast.SetStmt) (Plan, error) {
Expand Down
5 changes: 3 additions & 2 deletions planner/core/rule_column_pruning.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@
package core

import (
"fmt"

"github.com/pingcap/parser/ast"
"github.com/pingcap/parser/model"
"github.com/pingcap/tidb/expression"
"github.com/pingcap/tidb/infoschema"
log "github.com/sirupsen/logrus"
)

type columnPruner struct {
Expand All @@ -34,7 +35,7 @@ func getUsedList(usedCols []*expression.Column, schema *expression.Schema) []boo
for _, col := range usedCols {
idx := schema.ColumnIndex(col)
if idx == -1 {
log.Errorf("Can't find column %s from schema %s.", col, schema)
panic(fmt.Sprintf("Can't find column %s from schema %s.", col, schema))
}
used[idx] = true
}
Expand Down
4 changes: 4 additions & 0 deletions planner/core/rule_eliminate_projection.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ func canProjectionBeEliminatedLoose(p *LogicalProjection) bool {
// canProjectionBeEliminatedStrict checks whether a projection can be
// eliminated, returns true if the projection just copy its child's output.
func canProjectionBeEliminatedStrict(p *PhysicalProjection) bool {
// If this projection is specially added for `DO`, we keep it.
if p.CalculateNoDelay == true {
return false
}
if p.Schema().Len() == 0 {
return true
}
Expand Down

0 comments on commit 705341b

Please sign in to comment.