-
Notifications
You must be signed in to change notification settings - Fork 0
/
plan_ordering.go
131 lines (121 loc) · 4.33 KB
/
plan_ordering.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
// Copyright 2017 The Cockroach Authors.
//
// 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 sql
// planOrdering describes known ordering information for the rows generated by
// this node. The ordering information includes columns the output is ordered
// by and columns for which we know all rows have the same value. See
// orderingInfo for more details.
//
// Stable after optimizePlan() (or makePlan).
// Available after newPlan(), but may change on intermediate plan
// nodes during optimizePlan() due to index selection.
func planOrdering(plan planNode) orderingInfo {
switch n := plan.(type) {
case *explainPlanNode:
return planOrdering(n.results)
case *distinctNode:
return planOrdering(n.plan)
case *filterNode:
return planOrdering(n.source.plan)
case *limitNode:
return planOrdering(n.plan)
case *indexJoinNode:
return planOrdering(n.index)
case *groupNode:
// TODO(dt,knz,radu): aggregate buckets can be ordered if the source is
// ordered on the aggregating column already.
case *windowNode:
// TODO: window partitions can be ordered if the source is ordered
// appropriately.
case *joinNode:
return n.ordering
case *unionNode:
// TODO(knz): this can be ordered if the source is ordered already.
case *insertNode:
// TODO(knz): RETURNING is ordered by the PK.
case *deleteNode:
// TODO(knz): RETURNING is ordered by the PK.
case *updateNode:
// TODO(knz): RETURNING is ordered by the PK.
case *scanNode:
return n.ordering
case *ordinalityNode:
return n.ordering
case *renderNode:
return n.ordering
case *sortNode:
return sortOrdering(n)
}
// Every other node simply has no ordering guarantees on its output
// rows.
return orderingInfo{}
}
func sortOrdering(n *sortNode) orderingInfo {
underlying := planOrdering(n.plan)
var ord orderingInfo
if n.needSort {
// We will sort and can guarantee the desired ordering.
ord.ordering = make([]orderingColumnGroup, 0, len(n.ordering))
for _, o := range n.ordering {
// Skip any constant columns (we preserve them below).
if !underlying.constantCols.Contains(uint32(o.ColIdx)) {
ord.addColumn(o.ColIdx, o.Direction)
}
}
// Preserve constant columns.
ord.constantCols = underlying.constantCols.Copy()
} else {
// If we aren't sorting, the underlying plan's ordering can be more specific
// than the sortNode's ordering, so we want to use that. E.g:
// CREATE INDEX foo ON t (a, b);
// SELECT a, b, c FROM t ORDER BY a;
// We want to use (a, b) instead of just (a).
ord = underlying.copy()
}
// Remove constant columns not in the output.
for col, ok := ord.constantCols.Next(uint32(len(n.columns))); ok; col, ok = ord.constantCols.Next(col) {
ord.constantCols.Remove(col)
}
// The sortNode can project away columns, for queries like:
// SELECT k FROM kv ORDER BY v).
// Remove all the columns after the first one that's not present in
// the result columns.
for i, group := range ord.ordering {
// Check if the group has a column that is not present.
if missingCol, ok := group.cols.Next(uint32(len(n.columns))); ok {
if firstCol, ok := group.cols.Next(0); ok && firstCol < uint32(len(n.columns)) {
// The group has at least a column that is present. Remove the columns
// that are not present.
for ok := true; ok; missingCol, ok = group.cols.Next(missingCol + 1) {
group.cols.Remove(missingCol)
}
} else {
// None of the columns in the group are present. We need to break the
// orderingInfo here.
// If something is ordered by columns A, then B, then C, if I remove
// column B I can't say it's ordered by columns A, then C.
// Example:
// A | B | C A | C
// --------- -----
// 1 | 1 | 2 ---> 1 | 2
// 1 | 2 | 1 1 | 1
// 1 | 2 | 3 1 | 3
ord.ordering = ord.ordering[:i]
ord.isKey = false
break
}
}
}
return ord
}