vitess.io/vitess@v0.16.2/go/vt/vtgate/engine/comparer.go (about)

     1  /*
     2  Copyright 2021 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 engine
    18  
    19  import (
    20  	"vitess.io/vitess/go/mysql/collations"
    21  	"vitess.io/vitess/go/sqltypes"
    22  	"vitess.io/vitess/go/vt/vtgate/evalengine"
    23  )
    24  
    25  // comparer is the struct that has the logic for comparing two rows in the result set
    26  type comparer struct {
    27  	orderBy, weightString, starColFixedIndex int
    28  	collationID                              collations.ID
    29  	desc                                     bool
    30  }
    31  
    32  // compare compares two rows given the comparer and returns which one should be earlier in the result set
    33  // -1 if the first row should be earlier
    34  // 1 is the second row should be earlier
    35  // 0 if both the rows have equal ordering
    36  func (c *comparer) compare(r1, r2 []sqltypes.Value) (int, error) {
    37  	var colIndex int
    38  	if c.starColFixedIndex > c.orderBy && c.starColFixedIndex < len(r1) {
    39  		colIndex = c.starColFixedIndex
    40  	} else {
    41  		colIndex = c.orderBy
    42  	}
    43  	cmp, err := evalengine.NullsafeCompare(r1[colIndex], r2[colIndex], c.collationID)
    44  	if err != nil {
    45  		_, isComparisonErr := err.(evalengine.UnsupportedComparisonError)
    46  		_, isCollationErr := err.(evalengine.UnsupportedCollationError)
    47  		if !isComparisonErr && !isCollationErr || c.weightString == -1 {
    48  			return 0, err
    49  		}
    50  		// in case of a comparison or collation error switch to using the weight string column for ordering
    51  		c.orderBy = c.weightString
    52  		c.weightString = -1
    53  		cmp, err = evalengine.NullsafeCompare(r1[c.orderBy], r2[c.orderBy], c.collationID)
    54  		if err != nil {
    55  			return 0, err
    56  		}
    57  	}
    58  	// change the result if descending ordering is required
    59  	if c.desc {
    60  		cmp = -cmp
    61  	}
    62  	return cmp, nil
    63  }
    64  
    65  // extractSlices extracts the three fields of OrderByParams into a slice of comparers
    66  func extractSlices(input []OrderByParams) []*comparer {
    67  	var result []*comparer
    68  	for _, order := range input {
    69  		result = append(result, &comparer{
    70  			orderBy:           order.Col,
    71  			weightString:      order.WeightStringCol,
    72  			desc:              order.Desc,
    73  			starColFixedIndex: order.StarColFixedIndex,
    74  			collationID:       order.CollationID,
    75  		})
    76  	}
    77  	return result
    78  }