Skip to content

Commit e603a16

Browse files
committed
v3: revamp: simplify some relationships
This is a fundamental change in the relationships of some core data structures. Previously, every primitive was required to point at the symatb it was part of. At the same time, a symtab pointed at various primitives through the symbols it was holding. This was problematic when symtabs merged, which required the old symtabs to 'redirect' to the new ones. There was no clarity on when those redirects were applicable. There were places where it was not used. In this new code, the primitive->symtab relationship has been removed. A new top level planBuilder object now holds the symtab, along with other 'global' things like vschema, and the jointab. Most functions that needed the symtab have been made members of planBuilder. There are a few stray cases (members of the builder primitives) that still need it. In those cases, the symtab is passed in. But these are far and few. This has led to an overall simplification because this has caused most function signatures to shrink. There is also no ambiguity about the exact symtab being referenced. The route merge functionality had to be refactored. Some of those functions have moved to planBuilder. Also, newJoin was affected. Also, the code in newJoin was conceptually incorrect when handling left join. This has now been fixed to better represent the meaning of the functionality. In builder, LeftMost has been renamed to First, which is a more appropriate name. Also, while handling group by expressions, there were some risky type-casts. That has now been cleaned. If a group by is possible, then the analyzer returns an explicit object that can handle them. Signed-off-by: Sugu Sougoumarane <ssougou@gmail.com>
1 parent 0714ddd commit e603a16

File tree

18 files changed

+514
-551
lines changed

18 files changed

+514
-551
lines changed

go/vt/vtgate/engine/route.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,8 @@ func (route *Route) MarshalJSON() ([]byte, error) {
106106
}
107107

108108
// RouteOpcode is a number representing the opcode
109-
// for the Route primitve.
109+
// for the Route primitve. Adding new opcodes here
110+
// will require review of the join code in planbuilder.
110111
type RouteOpcode int
111112

112113
// This is the list of RouteOpcode values.

go/vt/vtgate/planbuilder/builder.go

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,6 @@ import (
3131
// builder defines the interface that a primitive must
3232
// satisfy.
3333
type builder interface {
34-
// Symtab returns the associated symtab.
35-
// Please copy code from an existing primitive to define this function.
36-
Symtab() *symtab
37-
3834
// Order is the execution order of the primitve. If there are subprimitves,
3935
// the order is one above the order of the subprimitives.
4036
// This is because the primitive executes its subprimitives first and
@@ -55,12 +51,13 @@ type builder interface {
5551
// Primitve returns the underlying primitive.
5652
Primitive() engine.Primitive
5753

58-
// Leftmost returns the leftmost builder.
59-
Leftmost() builder
54+
// First returns the first builder of the tree,
55+
// which is usually the left most.
56+
First() builder
6057

6158
// PushFilter pushes a WHERE or HAVING clause expression
6259
// to the specified origin.
63-
PushFilter(filter sqlparser.Expr, whereType string, origin builder) error
60+
PushFilter(pb *planBuilder, filter sqlparser.Expr, whereType string, origin builder) error
6461

6562
// PushSelect pushes the select expression to the specified
6663
// originator. If successful, the originator must create

go/vt/vtgate/planbuilder/delete.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,31 +33,31 @@ func buildDeletePlan(del *sqlparser.Delete, vschema ContextVSchema) (*engine.Del
3333
edel := &engine.Delete{
3434
Query: generateQuery(del),
3535
}
36-
bldr, err := processTableExprs(del.TableExprs, vschema)
37-
if err != nil {
36+
pb := newPlanBuilder(vschema, newJointab(sqlparser.GetBindvars(del)))
37+
if err := pb.processTableExprs(del.TableExprs); err != nil {
3838
return nil, err
3939
}
40-
rb, ok := bldr.(*route)
40+
rb, ok := pb.bldr.(*route)
4141
if !ok {
4242
return nil, errors.New("unsupported: multi-table delete statement in sharded keyspace")
4343
}
4444
edel.Keyspace = rb.ERoute.Keyspace
4545
if !edel.Keyspace.Sharded {
4646
// We only validate non-table subexpressions because the previous analysis has already validated them.
47-
if !validateSubquerySamePlan(rb.ERoute.Keyspace.Name, rb, vschema, del.Targets, del.Where, del.OrderBy, del.Limit) {
47+
if !pb.validateSubquerySamePlan(del.Targets, del.Where, del.OrderBy, del.Limit) {
4848
return nil, errors.New("unsupported: sharded subqueries in DML")
4949
}
5050
edel.Opcode = engine.DeleteUnsharded
5151
return edel, nil
5252
}
53-
if del.Targets != nil || len(rb.Symtab().tables) != 1 {
53+
if del.Targets != nil || len(pb.st.tables) != 1 {
5454
return nil, errors.New("unsupported: multi-table delete statement in sharded keyspace")
5555
}
5656
if hasSubquery(del) {
5757
return nil, errors.New("unsupported: subqueries in sharded DML")
5858
}
5959
var tableName sqlparser.TableName
60-
for t := range rb.Symtab().tables {
60+
for t := range pb.st.tables {
6161
tableName = t
6262
}
6363
table, _, destTabletType, destTarget, err := vschema.FindTable(tableName)

go/vt/vtgate/planbuilder/expr.go

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -79,39 +79,40 @@ func skipParenthesis(node sqlparser.Expr) sqlparser.Expr {
7979
//
8080
// If an expression has no references to the current query, then the left-most
8181
// origin is chosen as the default.
82-
func findOrigin(expr sqlparser.Expr, bldr builder) (origin builder, err error) {
83-
highestOrigin := bldr.Leftmost()
82+
func (pb *planBuilder) findOrigin(expr sqlparser.Expr) (origin builder, err error) {
83+
highestOrigin := pb.bldr.First()
8484
var subroutes []*route
8585
err = sqlparser.Walk(func(node sqlparser.SQLNode) (kontinue bool, err error) {
8686
switch node := node.(type) {
8787
case *sqlparser.ColName:
88-
newOrigin, isLocal, err := bldr.Symtab().Find(node)
88+
newOrigin, isLocal, err := pb.st.Find(node)
8989
if err != nil {
9090
return false, err
9191
}
9292
if isLocal && newOrigin.Order() > highestOrigin.Order() {
9393
highestOrigin = newOrigin
9494
}
9595
case *sqlparser.Subquery:
96-
var subplan builder
96+
spb := newPlanBuilder(pb.vschema, pb.jt)
9797
switch stmt := node.Select.(type) {
9898
case *sqlparser.Select:
99-
subplan, err = processSelect(stmt, bldr.Symtab().VSchema, bldr)
99+
if err := spb.processSelect(stmt, pb.st); err != nil {
100+
return false, err
101+
}
100102
case *sqlparser.Union:
101-
subplan, err = processUnion(stmt, bldr.Symtab().VSchema, bldr)
103+
if err := spb.processUnion(stmt, pb.st); err != nil {
104+
return false, err
105+
}
102106
default:
103107
panic(fmt.Sprintf("BUG: unexpected SELECT type: %T", node))
104108
}
105-
if err != nil {
106-
return false, err
107-
}
108-
subroute, isRoute := subplan.(*route)
109+
subroute, isRoute := spb.bldr.(*route)
109110
if !isRoute {
110111
return false, errors.New("unsupported: cross-shard query in subqueries")
111112
}
112-
for _, extern := range subroute.Symtab().Externs {
113+
for _, extern := range spb.st.Externs {
113114
// No error expected. These are resolved externs.
114-
newOrigin, isLocal, _ := bldr.Symtab().Find(extern)
115+
newOrigin, isLocal, _ := pb.st.Find(extern)
115116
if isLocal && newOrigin.Order() > highestOrigin.Order() {
116117
highestOrigin = newOrigin
117118
}
@@ -123,7 +124,7 @@ func findOrigin(expr sqlparser.Expr, bldr builder) (origin builder, err error) {
123124
if !node.Name.EqualString("last_insert_id") {
124125
return true, nil
125126
}
126-
if rb, isRoute := bldr.(*route); !isRoute || rb.ERoute.Keyspace.Sharded {
127+
if rb, isRoute := pb.bldr.(*route); !isRoute || rb.ERoute.Keyspace.Sharded {
127128
return false, errors.New("unsupported: LAST_INSERT_ID is only allowed for unsharded keyspaces")
128129
}
129130
}
@@ -137,7 +138,7 @@ func findOrigin(expr sqlparser.Expr, bldr builder) (origin builder, err error) {
137138
return nil, errors.New("unsupported: subquery cannot be merged with cross-shard subquery")
138139
}
139140
for _, subroute := range subroutes {
140-
if err := highestRoute.SubqueryCanMerge(subroute); err != nil {
141+
if err := highestRoute.SubqueryCanMerge(pb, subroute); err != nil {
141142
return nil, err
142143
}
143144
subroute.Redirect = highestRoute
@@ -157,7 +158,11 @@ func hasSubquery(node sqlparser.SQLNode) bool {
157158
return has
158159
}
159160

160-
func validateSubquerySamePlan(keyspace string, bldr builder, vschema ContextVSchema, nodes ...sqlparser.SQLNode) bool {
161+
func (pb *planBuilder) validateSubquerySamePlan(nodes ...sqlparser.SQLNode) bool {
162+
var keyspace string
163+
if rb, ok := pb.bldr.(*route); ok {
164+
keyspace = rb.ERoute.Keyspace.Name
165+
}
161166
samePlan := true
162167

163168
for _, node := range nodes {
@@ -171,12 +176,12 @@ func validateSubquerySamePlan(keyspace string, bldr builder, vschema ContextVSch
171176
if !inSubQuery {
172177
return true, nil
173178
}
174-
bldr, err := processSelect(nodeType, vschema, bldr)
175-
if err != nil {
179+
spb := newPlanBuilder(pb.vschema, pb.jt)
180+
if err := spb.processSelect(nodeType, pb.st); err != nil {
176181
samePlan = false
177182
return false, err
178183
}
179-
innerRoute, ok := bldr.(*route)
184+
innerRoute, ok := spb.bldr.(*route)
180185
if !ok {
181186
samePlan = false
182187
return false, errors.New("dummy")
@@ -189,12 +194,12 @@ func validateSubquerySamePlan(keyspace string, bldr builder, vschema ContextVSch
189194
if !inSubQuery {
190195
return true, nil
191196
}
192-
bldr, err := processUnion(nodeType, vschema, nil)
193-
if err != nil {
197+
spb := newPlanBuilder(pb.vschema, pb.jt)
198+
if err := spb.processUnion(nodeType, pb.st); err != nil {
194199
samePlan = false
195200
return false, err
196201
}
197-
innerRoute, ok := bldr.(*route)
202+
innerRoute, ok := spb.bldr.(*route)
198203
if !ok {
199204
samePlan = false
200205
return false, errors.New("dummy")

0 commit comments

Comments
 (0)