-
Notifications
You must be signed in to change notification settings - Fork 4
/
builder.go
174 lines (150 loc) · 6.62 KB
/
builder.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
/*
Copyright 2017 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package planbuilder
import (
"errors"
"fmt"
"gopkg.in/src-d/go-vitess.v1/vt/key"
"gopkg.in/src-d/go-vitess.v1/vt/sqlparser"
"gopkg.in/src-d/go-vitess.v1/vt/vtgate/engine"
"gopkg.in/src-d/go-vitess.v1/vt/vtgate/vindexes"
topodatapb "gopkg.in/src-d/go-vitess.v1/vt/proto/topodata"
)
// 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(expr *sqlparser.AliasedExpr, origin builder) (rc *resultColumn, colnum int, err error)
// MakeDistinct makes the primitive handle the distinct clause.
MakeDistinct() 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.SQLVal)
// PushMisc pushes miscelleaneous constructs to all the primitives.
PushMisc(sel *sqlparser.Select)
// 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, colnum int)
// 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 {
FindTable(tablename sqlparser.TableName) (*vindexes.Table, string, topodatapb.TabletType, key.Destination, error)
FindTablesOrVindex(tablename sqlparser.TableName) ([]*vindexes.Table, vindexes.Vindex, string, topodatapb.TabletType, key.Destination, error)
DefaultKeyspace() (*vindexes.Keyspace, error)
TargetString() string
}
// Build builds a plan for a query based on the specified vschema.
// It's the main entry point for this package.
func Build(query string, vschema ContextVSchema) (*engine.Plan, error) {
stmt, err := sqlparser.Parse(query)
if err != nil {
return nil, err
}
return BuildFromStmt(query, stmt, vschema)
}
// BuildFromStmt builds a plan based on the AST provided.
// TODO(sougou): The query input is trusted as the source
// of the AST. Maybe this function just returns instructions
// and engine.Plan can be built by the caller.
func BuildFromStmt(query string, stmt sqlparser.Statement, vschema ContextVSchema) (*engine.Plan, error) {
var err error
plan := &engine.Plan{
Original: query,
}
switch stmt := stmt.(type) {
case *sqlparser.Select:
plan.Instructions, err = buildSelectPlan(stmt, vschema)
case *sqlparser.Insert:
plan.Instructions, err = buildInsertPlan(stmt, vschema)
case *sqlparser.Update:
plan.Instructions, err = buildUpdatePlan(stmt, vschema)
case *sqlparser.Delete:
plan.Instructions, err = buildDeletePlan(stmt, vschema)
case *sqlparser.Union:
plan.Instructions, err = buildUnionPlan(stmt, vschema)
case *sqlparser.Set:
return nil, errors.New("unsupported construct: set")
case *sqlparser.Show:
return nil, errors.New("unsupported construct: show")
case *sqlparser.DDL:
return nil, errors.New("unsupported construct: ddl")
case *sqlparser.DBDDL:
return nil, errors.New("unsupported construct: ddl on database")
case *sqlparser.OtherRead:
return nil, errors.New("unsupported construct: other read")
case *sqlparser.OtherAdmin:
return nil, errors.New("unsupported construct: other admin")
case *sqlparser.Begin:
return nil, errors.New("unsupported construct: begin")
case *sqlparser.Commit:
return nil, errors.New("unsupported construct: commit")
case *sqlparser.Rollback:
return nil, errors.New("unsupported construct: rollback")
default:
panic(fmt.Sprintf("BUG: unexpected statement type: %T", stmt))
}
if err != nil {
return nil, err
}
return plan, nil
}