Skip to content

Commit

Permalink
Merge pull request vitessio#7054 from systay/planner-refactor-2
Browse files Browse the repository at this point in the history
Refactoring of plan building
  • Loading branch information
systay authored Nov 23, 2020
2 parents cf9caa3 + 42099a2 commit faf2525
Show file tree
Hide file tree
Showing 32 changed files with 1,446 additions and 1,422 deletions.
4 changes: 2 additions & 2 deletions go/test/endtoend/vtgate/misc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -498,12 +498,12 @@ func assertMatchesNoOrder(t *testing.T, conn *mysql.Conn, query, expected string
func assertIsEmpty(t *testing.T, conn *mysql.Conn, query string) {
t.Helper()
qr := exec(t, conn, query)
assert.Empty(t, qr.Rows)
assert.Empty(t, qr.Rows, "for query: "+query)
}

func exec(t *testing.T, conn *mysql.Conn, query string) *sqltypes.Result {
t.Helper()
qr, err := conn.ExecuteFetch(query, 1000, true)
require.NoError(t, err)
require.NoError(t, err, "for query: "+query)
return qr
}
1 change: 1 addition & 0 deletions go/vt/sqlparser/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ type (
AddOrder(*Order)
SetLimit(*Limit)
SetLock(lock Lock)
MakeDistinct()
SQLNode
}

Expand Down
15 changes: 15 additions & 0 deletions go/vt/sqlparser/ast_funcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -723,6 +723,11 @@ func (node *Select) SetLock(lock Lock) {
node.Lock = lock
}

// MakeDistinct makes the statement distinct
func (node *Select) MakeDistinct() {
node.Distinct = true
}

// AddWhere adds the boolean expression to the
// WHERE clause as an AND condition.
func (node *Select) AddWhere(expr Expr) {
Expand Down Expand Up @@ -770,6 +775,11 @@ func (node *ParenSelect) SetLock(lock Lock) {
node.Select.SetLock(lock)
}

// MakeDistinct implements the SelectStatement interface
func (node *ParenSelect) MakeDistinct() {
node.Select.MakeDistinct()
}

// AddOrder adds an order by element
func (node *Union) AddOrder(order *Order) {
node.OrderBy = append(node.OrderBy, order)
Expand All @@ -785,6 +795,11 @@ func (node *Union) SetLock(lock Lock) {
node.Lock = lock
}

// MakeDistinct implements the SelectStatement interface
func (node *Union) MakeDistinct() {
node.UnionSelects[len(node.UnionSelects)-1].Distinct = true
}

//Unionize returns a UNION, either creating one or adding SELECT to an existing one
func Unionize(lhs, rhs SelectStatement, distinct bool, by OrderBy, limit *Limit, lock Lock) *Union {
union, isUnion := lhs.(*Union)
Expand Down
213 changes: 0 additions & 213 deletions go/vt/vtgate/planbuilder/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,96 +33,6 @@ import (
vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc"
)

//-------------------------------------------------------------------------

// builder defines the interface that a primitive must
// satisfy.
type builder interface {
// Order is the execution order of the primitive. If there are subprimitives,
// the order is one above the order of the subprimitives.
// This is because the primitive executes its subprimitives first and
// processes their results to generate its own values.
// Please copy code from an existing primitive to define this function.
Order() int

// ResultColumns returns the list of result columns the
// primitive returns.
// Please copy code from an existing primitive to define this function.
ResultColumns() []*resultColumn

// Reorder reassigns order for the primitive and its sub-primitives.
// The input is the order of the previous primitive that should
// execute before this one.
Reorder(int)

// First returns the first builder of the tree,
// which is usually the left most.
First() builder

// PushFilter pushes a WHERE or HAVING clause expression
// to the specified origin.
PushFilter(pb *primitiveBuilder, filter sqlparser.Expr, whereType string, origin builder) error

// PushSelect pushes the select expression to the specified
// originator. If successful, the originator must create
// a resultColumn entry and return it. The top level caller
// must accumulate these result columns and set the symtab
// after analysis.
PushSelect(pb *primitiveBuilder, expr *sqlparser.AliasedExpr, origin builder) (rc *resultColumn, colNumber int, err error)

// MakeDistinct makes the primitive handle the distinct clause.
MakeDistinct() (builder, error)
// PushGroupBy makes the primitive handle the GROUP BY clause.
PushGroupBy(sqlparser.GroupBy) error

// PushOrderBy pushes the ORDER BY clause. It returns the
// the current primitive or a replacement if a new one was
// created.
PushOrderBy(sqlparser.OrderBy) (builder, error)

// SetUpperLimit is an optimization hint that tells that primitive
// that it does not need to return more than the specified number of rows.
// A primitive that cannot perform this can ignore the request.
SetUpperLimit(count sqlparser.Expr)

// PushMisc pushes miscelleaneous constructs to all the primitives.
PushMisc(sel *sqlparser.Select) error

// Wireup performs the wire-up work. Nodes should be traversed
// from right to left because the rhs nodes can request vars from
// the lhs nodes.
Wireup(bldr builder, jt *jointab) error

// SupplyVar finds the common root between from and to. If it's
// the common root, it supplies the requested var to the rhs tree.
// If the primitive already has the column in its list, it should
// just supply it to the 'to' node. Otherwise, it should request
// for it by calling SupplyCol on the 'from' sub-tree to request the
// column, and then supply it to the 'to' node.
SupplyVar(from, to int, col *sqlparser.ColName, varname string)

// SupplyCol is meant to be used for the wire-up process. This function
// changes the primitive to supply the requested column and returns
// the resultColumn and column number of the result. SupplyCol
// is different from PushSelect because it may reuse an existing
// resultColumn, whereas PushSelect guarantees the addition of a new
// result column and returns a distinct symbol for it.
SupplyCol(col *sqlparser.ColName) (rc *resultColumn, colNumber int)

// SupplyWeightString must supply a weight_string expression of the
// specified column.
SupplyWeightString(colNumber int) (weightcolNumber int, err error)

// PushLock pushes "FOR UPDATE", "LOCK IN SHARE MODE" down to all routes
PushLock(lock sqlparser.Lock) error

// Primitive returns the underlying primitive.
// This function should only be called after Wireup is finished.
Primitive() engine.Primitive
}

//-------------------------------------------------------------------------

// ContextVSchema defines the interface for this package to fetch
// info about tables.
type ContextVSchema interface {
Expand All @@ -139,133 +49,10 @@ type ContextVSchema interface {
KeyspaceExists(keyspace string) bool
}

//-------------------------------------------------------------------------

// builderCommon implements some common functionality of builders.
// Make sure to override in case behavior needs to be changed.
type builderCommon struct {
order int
input builder
}

func newBuilderCommon(input builder) builderCommon {
return builderCommon{input: input}
}

func (bc *builderCommon) Order() int {
return bc.order
}

func (bc *builderCommon) Reorder(order int) {
bc.input.Reorder(order)
bc.order = bc.input.Order() + 1
}

func (bc *builderCommon) First() builder {
return bc.input.First()
}

func (bc *builderCommon) ResultColumns() []*resultColumn {
return bc.input.ResultColumns()
}

func (bc *builderCommon) SetUpperLimit(count sqlparser.Expr) {
bc.input.SetUpperLimit(count)
}

func (bc *builderCommon) PushMisc(sel *sqlparser.Select) error {
return bc.input.PushMisc(sel)
}

func (bc *builderCommon) Wireup(bldr builder, jt *jointab) error {
return bc.input.Wireup(bldr, jt)
}

func (bc *builderCommon) SupplyVar(from, to int, col *sqlparser.ColName, varname string) {
bc.input.SupplyVar(from, to, col, varname)
}

func (bc *builderCommon) SupplyCol(col *sqlparser.ColName) (rc *resultColumn, colNumber int) {
return bc.input.SupplyCol(col)
}

func (bc *builderCommon) SupplyWeightString(colNumber int) (weightcolNumber int, err error) {
return bc.input.SupplyWeightString(colNumber)
}

//-------------------------------------------------------------------------

type truncater interface {
SetTruncateColumnCount(int)
}

// resultsBuilder is a superset of builderCommon. It also handles
// resultsColumn functionality.
type resultsBuilder struct {
builderCommon
resultColumns []*resultColumn
weightStrings map[*resultColumn]int
truncater truncater
}

func newResultsBuilder(input builder, truncater truncater) resultsBuilder {
return resultsBuilder{
builderCommon: newBuilderCommon(input),
resultColumns: input.ResultColumns(),
weightStrings: make(map[*resultColumn]int),
truncater: truncater,
}
}

func (rsb *resultsBuilder) ResultColumns() []*resultColumn {
return rsb.resultColumns
}

// SupplyCol is currently unreachable because the builders using resultsBuilder
// are currently above a join, which is the only builder that uses it for now.
// This can change if we start supporting correlated subqueries.
func (rsb *resultsBuilder) SupplyCol(col *sqlparser.ColName) (rc *resultColumn, colNumber int) {
c := col.Metadata.(*column)
for i, rc := range rsb.resultColumns {
if rc.column == c {
return rc, i
}
}
rc, colNumber = rsb.input.SupplyCol(col)
if colNumber < len(rsb.resultColumns) {
return rc, colNumber
}
// Add result columns from input until colNumber is reached.
for colNumber >= len(rsb.resultColumns) {
rsb.resultColumns = append(rsb.resultColumns, rsb.input.ResultColumns()[len(rsb.resultColumns)])
}
rsb.truncater.SetTruncateColumnCount(len(rsb.resultColumns))
return rc, colNumber
}

func (rsb *resultsBuilder) SupplyWeightString(colNumber int) (weightcolNumber int, err error) {
rc := rsb.resultColumns[colNumber]
if weightcolNumber, ok := rsb.weightStrings[rc]; ok {
return weightcolNumber, nil
}
weightcolNumber, err = rsb.input.SupplyWeightString(colNumber)
if err != nil {
return 0, nil
}
rsb.weightStrings[rc] = weightcolNumber
if weightcolNumber < len(rsb.resultColumns) {
return weightcolNumber, nil
}
// Add result columns from input until weightcolNumber is reached.
for weightcolNumber >= len(rsb.resultColumns) {
rsb.resultColumns = append(rsb.resultColumns, rsb.input.ResultColumns()[len(rsb.resultColumns)])
}
rsb.truncater.SetTruncateColumnCount(len(rsb.resultColumns))
return weightcolNumber, nil
}

//-------------------------------------------------------------------------

// Build builds a plan for a query based on the specified vschema.
// This method is only used from tests
func Build(query string, vschema ContextVSchema) (*engine.Plan, error) {
Expand Down
Loading

0 comments on commit faf2525

Please sign in to comment.