forked from vitessio/vitess
-
Notifications
You must be signed in to change notification settings - Fork 0
/
postprocess.go
159 lines (151 loc) · 4.39 KB
/
postprocess.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
// Copyright 2016, Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package planbuilder
import (
"errors"
"fmt"
"strconv"
"github.com/youtube/vitess/go/vt/sqlparser"
"github.com/youtube/vitess/go/vt/vtgate/vindexes"
)
// This file has functions to analyze postprocessing
// clauses like GROUP BY, etc.
// pushGroupBy processes the group by clause. It resolves all symbols,
// and ensures that there are no subqueries.
func pushGroupBy(groupBy sqlparser.GroupBy, bldr builder) error {
if groupBy == nil {
return nil
}
rb, ok := bldr.(*route)
if !ok {
return errors.New("unsupported: complex join and group by")
}
err := sqlparser.Walk(func(node sqlparser.SQLNode) (kontinue bool, err error) {
switch node := node.(type) {
case *sqlparser.ColName:
_, _, err := bldr.Symtab().Find(node, true)
if err != nil {
return false, err
}
case *sqlparser.Subquery:
return false, errors.New("unsupported: subqueries in group by expression")
}
return true, nil
}, groupBy)
if err != nil {
return err
}
if rb.IsSingle() {
rb.SetGroupBy(groupBy)
return nil
}
// It's a scatter route. We can allow group by if it references a
// column with a unique vindex.
for _, expr := range groupBy {
vindex := bldr.Symtab().Vindex(expr, rb, true)
if vindex != nil && vindexes.IsUnique(vindex) {
rb.SetGroupBy(groupBy)
return nil
}
}
return errors.New("unsupported: scatter and group by")
}
// pushOrderBy pushes the order by clause to the appropriate routes.
// In the case of a join, this is allowed only if the order by columns
// match the join order. Otherwise, it's an error.
// If column numbers were used to reference the columns, those numbers
// are readjusted on push-down to match the numbers of the individual
// queries.
func pushOrderBy(orderBy sqlparser.OrderBy, bldr builder) error {
switch len(orderBy) {
case 0:
return nil
case 1:
// Special handling for ORDER BY NULL. Push it everywhere.
if _, ok := orderBy[0].Expr.(*sqlparser.NullVal); ok {
bldr.PushOrderByNull()
return nil
}
}
routeNumber := 0
for _, order := range orderBy {
// Only generator is allowed to change the AST.
// If we have to change the order by expression,
// we have to build a new node.
pushOrder := order
var rb *route
if node, ok := order.Expr.(*sqlparser.SQLVal); ok && node.Type == sqlparser.IntVal {
num, err := strconv.ParseInt(string(node.Val), 0, 64)
if err != nil {
return fmt.Errorf("error parsing order by clause: %s", sqlparser.String(node))
}
if num < 1 || num > int64(len(bldr.Symtab().Colsyms)) {
return errors.New("order by column number out of range")
}
colsym := bldr.Symtab().Colsyms[num-1]
rb = colsym.Route()
// We have to recompute the column number.
for num, s := range rb.Colsyms {
if s == colsym {
pushOrder = &sqlparser.Order{
Expr: sqlparser.NewIntVal(strconv.AppendInt(nil, int64(num+1), 10)),
Direction: order.Direction,
}
}
}
if pushOrder == order {
panic("unexpected: column not found for order by")
}
} else {
// Analyze column references within the expression to make sure they all
// go to the same route.
err := sqlparser.Walk(func(node sqlparser.SQLNode) (kontinue bool, err error) {
switch node := node.(type) {
case *sqlparser.ColName:
curRoute, _, err := bldr.Symtab().Find(node, true)
if err != nil {
return false, err
}
if rb == nil || rb == curRoute {
rb = curRoute
return true, nil
}
return false, errors.New("unsupported: complex join and complex order by")
}
return true, nil
}, order.Expr)
if err != nil {
return err
}
}
if rb == nil {
return errors.New("unsupported: complex order by")
}
if rb.Order() < routeNumber {
return errors.New("unsupported: complex join and out of sequence order by")
}
if !rb.IsSingle() {
return errors.New("unsupported: scatter and order by")
}
routeNumber = rb.Order()
if err := rb.AddOrder(pushOrder); err != nil {
return err
}
}
return nil
}
func pushLimit(limit *sqlparser.Limit, bldr builder) error {
if limit == nil {
return nil
}
rb, ok := bldr.(*route)
if !ok {
return errors.New("unsupported: limits with complex joins")
}
if !rb.IsSingle() {
return errors.New("unsupported: limits with scatter")
}
rb.SetLimit(limit)
return nil
}