vitess.io/vitess@v0.16.2/go/vt/vtgate/planbuilder/merge_sort.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/sqltypes" 21 "vitess.io/vitess/go/vt/sqlparser" 22 "vitess.io/vitess/go/vt/vtgate/engine" 23 "vitess.io/vitess/go/vt/vtgate/planbuilder/plancontext" 24 ) 25 26 var _ logicalPlan = (*mergeSort)(nil) 27 28 // mergeSort is a pseudo-primitive. It amends the 29 // the underlying Route to perform a merge sort. 30 // It's differentiated as a separate primitive 31 // because some operations cannot be pushed down, 32 // which would otherwise be possible with a simple route. 33 // Since ORDER BY happens near the end of the SQL processing, 34 // most functions of this primitive are unreachable. 35 type mergeSort struct { 36 resultsBuilder 37 truncateColumnCount int 38 } 39 40 // newMergeSort builds a new mergeSort. 41 func newMergeSort(rb *route) *mergeSort { 42 ms := &mergeSort{ 43 resultsBuilder: newResultsBuilder(rb, nil), 44 } 45 ms.truncater = ms 46 return ms 47 } 48 49 // SetTruncateColumnCount satisfies the truncater interface. 50 // This function records the truncate column count and sets 51 // it later on the eroute during wire-up phase. 52 func (ms *mergeSort) SetTruncateColumnCount(count int) { 53 ms.truncateColumnCount = count 54 } 55 56 // Primitive implements the logicalPlan interface 57 func (ms *mergeSort) Primitive() engine.Primitive { 58 return ms.input.Primitive() 59 } 60 61 // Wireup implements the logicalPlan interface 62 func (ms *mergeSort) Wireup(plan logicalPlan, jt *jointab) error { 63 // If the route has to do the ordering, and if any columns are Text, 64 // we have to request the corresponding weight_string from mysql 65 // and use that value instead. This is because we cannot mimic 66 // mysql's collation behavior yet. 67 rb := ms.input.(*route) 68 for i, orderby := range rb.eroute.OrderBy { 69 rc := ms.resultColumns[orderby.Col] 70 // Add a weight_string column if we know that the column is a textual column or if its type is unknown 71 if sqltypes.IsText(rc.column.typ) || rc.column.typ == sqltypes.Null { 72 var err error 73 rb.eroute.OrderBy[i].WeightStringCol, err = rb.SupplyWeightString(orderby.Col, orderby.FromGroupBy) 74 if err != nil { 75 _, isUnsupportedErr := err.(UnsupportedSupplyWeightString) 76 if isUnsupportedErr { 77 continue 78 } 79 return err 80 } 81 ms.truncateColumnCount = len(ms.resultColumns) 82 } 83 } 84 rb.eroute.TruncateColumnCount = ms.truncateColumnCount 85 return ms.input.Wireup(plan, jt) 86 } 87 88 func (ms *mergeSort) WireupGen4(ctx *plancontext.PlanningContext) error { 89 return ms.input.WireupGen4(ctx) 90 } 91 92 // OutputColumns implements the logicalPlan interface 93 func (ms *mergeSort) OutputColumns() []sqlparser.SelectExpr { 94 outputCols := ms.input.OutputColumns() 95 if ms.truncateColumnCount > 0 { 96 return outputCols[:ms.truncateColumnCount] 97 } 98 return outputCols 99 }