vitess.io/vitess@v0.16.2/go/vt/vtgate/planbuilder/postprocess.go (about) 1 /* 2 Copyright 2019 The Vitess Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package planbuilder 18 19 import ( 20 "vitess.io/vitess/go/mysql/collations" 21 "vitess.io/vitess/go/vt/sqlparser" 22 "vitess.io/vitess/go/vt/vterrors" 23 "vitess.io/vitess/go/vt/vtgate/evalengine" 24 "vitess.io/vitess/go/vt/vtgate/semantics" 25 ) 26 27 // This file has functions to analyze postprocessing 28 // clauses like ORDER BY, etc. 29 30 // pushGroupBy processes the group by clause. It resolves all symbols 31 // and ensures that there are no subqueries. 32 func (pb *primitiveBuilder) pushGroupBy(sel *sqlparser.Select) error { 33 if sel.Distinct { 34 newBuilder, err := planDistinct(pb.plan) 35 if err != nil { 36 return err 37 } 38 pb.plan = newBuilder 39 } 40 41 if err := pb.st.ResolveSymbols(sel.GroupBy); err != nil { 42 return err 43 } 44 45 newInput, err := planGroupBy(pb, pb.plan, sel.GroupBy) 46 if err != nil { 47 return err 48 } 49 pb.plan = newInput 50 51 return nil 52 } 53 54 // pushOrderBy pushes the order by clause into the primitives. 55 // It resolves all symbols and ensures that there are no subqueries. 56 func (pb *primitiveBuilder) pushOrderBy(orderBy sqlparser.OrderBy) error { 57 if err := pb.st.ResolveSymbols(orderBy); err != nil { 58 return err 59 } 60 var v3OrderBylist v3OrderBy 61 for _, order := range orderBy { 62 v3OrderBylist = append(v3OrderBylist, &v3Order{Order: order}) 63 } 64 plan, err := planOrdering(pb, pb.plan, v3OrderBylist) 65 if err != nil { 66 return err 67 } 68 pb.plan = plan 69 pb.plan.Reorder(0) 70 return nil 71 } 72 73 func (pb *primitiveBuilder) pushLimit(limit *sqlparser.Limit) error { 74 if limit == nil { 75 return nil 76 } 77 rb, ok := pb.plan.(*route) 78 if ok && rb.isSingleShard() { 79 rb.SetLimit(limit) 80 return nil 81 } 82 83 lb, err := createLimit(pb.plan, limit) 84 if err != nil { 85 return err 86 } 87 88 plan, err := visit(lb, setUpperLimit) 89 if err != nil { 90 return err 91 } 92 93 pb.plan = plan 94 pb.plan.Reorder(0) 95 return nil 96 } 97 98 // make sure we have the right signature for this function 99 var _ planVisitor = setUpperLimit 100 101 // setUpperLimit is an optimization hint that tells that primitive 102 // that it does not need to return more than the specified number of rows. 103 // A primitive that cannot perform this can ignore the request. 104 func setUpperLimit(plan logicalPlan) (bool, logicalPlan, error) { 105 switch node := plan.(type) { 106 case *join, *joinGen4, *hashJoin: 107 return false, node, nil 108 case *memorySort: 109 pv := evalengine.NewBindVar("__upper_limit", collations.TypedCollation{}) 110 node.eMemorySort.UpperLimit = pv 111 // we don't want to go down to the rest of the tree 112 return false, node, nil 113 case *pulloutSubquery: 114 // we control the visitation manually here - 115 // we don't want to visit the subQuery side of this plan 116 newUnderlying, err := visit(node.underlying, setUpperLimit) 117 if err != nil { 118 return false, nil, err 119 } 120 121 node.underlying = newUnderlying 122 return false, node, nil 123 case *route: 124 // The route pushes the limit regardless of the plan. 125 // If it's a scatter query, the rows returned will be 126 // more than the upper limit, but enough for the limit 127 node.Select.SetLimit(&sqlparser.Limit{Rowcount: sqlparser.NewArgument("__upper_limit")}) 128 case *routeGen4: 129 // The route pushes the limit regardless of the plan. 130 // If it's a scatter query, the rows returned will be 131 // more than the upper limit, but enough for the limit 132 node.Select.SetLimit(&sqlparser.Limit{Rowcount: sqlparser.NewArgument("__upper_limit")}) 133 case *concatenate: 134 return false, node, nil 135 } 136 return true, plan, nil 137 } 138 139 func createLimit(input logicalPlan, limit *sqlparser.Limit) (logicalPlan, error) { 140 plan := newLimit(input) 141 emptySemTable := semantics.EmptySemTable() 142 pv, err := evalengine.Translate(limit.Rowcount, emptySemTable) 143 if err != nil { 144 return nil, vterrors.Wrap(err, "unexpected expression in LIMIT") 145 } 146 plan.elimit.Count = pv 147 148 if limit.Offset != nil { 149 pv, err = evalengine.Translate(limit.Offset, emptySemTable) 150 if err != nil { 151 return nil, vterrors.Wrap(err, "unexpected expression in OFFSET") 152 } 153 plan.elimit.Offset = pv 154 } 155 156 return plan, nil 157 }