-
Notifications
You must be signed in to change notification settings - Fork 218
Expand file tree
/
Copy pathplan_node.go
More file actions
130 lines (117 loc) · 2.78 KB
/
plan_node.go
File metadata and controls
130 lines (117 loc) · 2.78 KB
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
/*
* Radon
*
* Copyright 2018 The Radon Authors.
* Code is licensed under the GPLv3.
*
*/
package builder
import (
"xcontext"
"github.com/xelabs/go-mysqlstack/sqlparser"
)
// PlanNode interface.
type PlanNode interface {
addNoTableFilter(exprs []sqlparser.Expr)
buildQuery(root PlanNode)
calcRoute() (PlanNode, error)
Children() []ChildPlan
getFields() []selectTuple
getReferTables() map[string]*tableInfo
GetQuery() []xcontext.QueryTuple
pushSelectExprs(fields, groups []selectTuple, sel *sqlparser.Select, aggTyp aggrType) error
pushSelectExpr(field selectTuple) (int, error)
pushFilter(filter exprInfo) error
pushKeyFilter(filter exprInfo, table, field string) error
pushHaving(having exprInfo) error
pushOrderBy(orderBy sqlparser.OrderBy) error
pushLimit(limit *sqlparser.Limit) error
pushMisc(sel *sqlparser.Select)
reOrder(int)
setParent(p *JoinNode)
Order() int
}
// findLCA get the two plannode's lowest common ancestors node.
func findLCA(h, p1, p2 PlanNode) PlanNode {
if p1 == h || p2 == h {
return h
}
jn, ok := h.(*JoinNode)
if !ok {
return nil
}
pl := findLCA(jn.Left, p1, p2)
pr := findLCA(jn.Right, p1, p2)
if pl != nil && pr != nil {
return jn
}
if pl == nil {
return pr
}
return pl
}
// setParenthese is only used in JoinNode and MergeNode.
func setParenthese(node PlanNode, hasParen bool) {
switch node := node.(type) {
case *JoinNode:
node.hasParen = hasParen
case *MergeNode:
node.hasParen = hasParen
}
}
func findParent(tables []string, node PlanNode) PlanNode {
var parent PlanNode
for _, tb := range tables {
tbInfo := node.getReferTables()[tb]
if parent == nil {
parent = tbInfo.parent
continue
}
if parent != tbInfo.parent {
parent = findLCA(node, parent, tbInfo.parent)
}
}
return parent
}
func addFilter(s PlanNode, filter exprInfo) {
switch node := s.(type) {
case *JoinNode:
node.otherFilter = append(node.otherFilter, filter)
case *MergeNode:
node.addWhere(filter.expr)
}
}
// pushFilters push a WHERE clause down, and update the PlanNode info.
func pushFilters(s PlanNode, expr sqlparser.Expr) (PlanNode, error) {
joins, filters, err := parseWhereOrJoinExprs(expr, s.getReferTables())
if err != nil {
return s, err
}
for _, filter := range filters {
if err := s.pushFilter(filter); err != nil {
return s, err
}
}
switch node := s.(type) {
case *MergeNode:
for _, joinCond := range joins {
node.addWhere(joinCond.expr)
}
case *JoinNode:
return node.pushEqualCmprs(joins), nil
}
return s, nil
}
// pushHavings push a HAVING clause down.
func pushHavings(s PlanNode, expr sqlparser.Expr) error {
havings, err := parseHaving(expr, s.getFields())
if err != nil {
return err
}
for _, having := range havings {
if err = s.pushHaving(having); err != nil {
return err
}
}
return nil
}