github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/colexec/sort_tmpl.go (about)

     1  // Copyright 2018 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  // {{/*
    12  // +build execgen_template
    13  //
    14  // This file is the execgen template for sort.eg.go. It's formatted in a
    15  // special way, so it's both valid Go and a valid text/template input. This
    16  // permits editing this file with editor support.
    17  //
    18  // */}}
    19  
    20  package colexec
    21  
    22  import (
    23  	"context"
    24  	"fmt"
    25  
    26  	"github.com/cockroachdb/cockroach/pkg/col/coldata"
    27  	"github.com/cockroachdb/cockroach/pkg/col/typeconv"
    28  	"github.com/cockroachdb/cockroach/pkg/sql/colexec/execgen"
    29  	"github.com/cockroachdb/cockroach/pkg/sql/colexecbase/colexecerror"
    30  	"github.com/cockroachdb/cockroach/pkg/sql/execinfrapb"
    31  	"github.com/cockroachdb/cockroach/pkg/sql/types"
    32  )
    33  
    34  // Remove unused warning.
    35  var _ = execgen.UNSAFEGET
    36  
    37  // {{/*
    38  
    39  // Declarations to make the template compile properly.
    40  
    41  // _GOTYPESLICE is the template variable.
    42  type _GOTYPESLICE interface{}
    43  
    44  // _CANONICAL_TYPE_FAMILY is the template variable.
    45  const _CANONICAL_TYPE_FAMILY = types.UnknownFamily
    46  
    47  // _TYPE_WIDTH is the template variable.
    48  const _TYPE_WIDTH = 0
    49  
    50  // _DIR_ENUM is the template variable.
    51  const _DIR_ENUM = 0
    52  
    53  // _ISNULL is the template type variable for whether the sorter handles nulls
    54  // or not. It will be replaced by the appropriate boolean.
    55  const _ISNULL = false
    56  
    57  // _ASSIGN_LT is the template equality function for assigning the first input
    58  // to the result of the second input < the third input.
    59  func _ASSIGN_LT(_, _, _, _, _, _ string) bool {
    60  	colexecerror.InternalError("")
    61  }
    62  
    63  // */}}
    64  
    65  func isSorterSupported(t *types.T, dir execinfrapb.Ordering_Column_Direction) bool {
    66  	// {{range .}}
    67  	// {{if .Nulls}}
    68  	switch dir {
    69  	// {{range .DirOverloads}}
    70  	case _DIR_ENUM:
    71  		switch typeconv.TypeFamilyToCanonicalTypeFamily(t.Family()) {
    72  		// {{range .FamilyOverloads}}
    73  		case _CANONICAL_TYPE_FAMILY:
    74  			switch t.Width() {
    75  			// {{range .WidthOverloads}}
    76  			case _TYPE_WIDTH:
    77  				return true
    78  				// {{end}}
    79  			}
    80  			// {{end}}
    81  		}
    82  		// {{end}}
    83  	}
    84  	// {{end}}
    85  	// {{end}}
    86  	return false
    87  }
    88  
    89  func newSingleSorter(
    90  	t *types.T, dir execinfrapb.Ordering_Column_Direction, hasNulls bool,
    91  ) colSorter {
    92  	switch hasNulls {
    93  	// {{range .}}
    94  	// {{$nulls := .Nulls}}
    95  	case _ISNULL:
    96  		switch dir {
    97  		// {{range .DirOverloads}}
    98  		// {{$dir := .DirString}}
    99  		case _DIR_ENUM:
   100  			switch typeconv.TypeFamilyToCanonicalTypeFamily(t.Family()) {
   101  			// {{range .FamilyOverloads}}
   102  			case _CANONICAL_TYPE_FAMILY:
   103  				switch t.Width() {
   104  				// {{range .WidthOverloads}}
   105  				case _TYPE_WIDTH:
   106  					return &sort_TYPE_DIR_HANDLES_NULLSOp{}
   107  					// {{end}}
   108  				}
   109  				// {{end}}
   110  			}
   111  			// {{end}}
   112  		}
   113  		// {{end}}
   114  	}
   115  	colexecerror.InternalError("isSorterSupported should have caught this")
   116  	// This code is unreachable, but the compiler cannot infer that.
   117  	return nil
   118  }
   119  
   120  // {{range .}}
   121  // {{$nulls := .Nulls}}
   122  // {{range .DirOverloads}}
   123  // {{$dir := .DirString}}
   124  // {{range .FamilyOverloads}}
   125  // {{range .WidthOverloads}}
   126  
   127  type sort_TYPE_DIR_HANDLES_NULLSOp struct {
   128  	sortCol       _GOTYPESLICE
   129  	nulls         *coldata.Nulls
   130  	order         []int
   131  	cancelChecker CancelChecker
   132  }
   133  
   134  func (s *sort_TYPE_DIR_HANDLES_NULLSOp) init(col coldata.Vec, order []int) {
   135  	s.sortCol = col.TemplateType()
   136  	s.nulls = col.Nulls()
   137  	s.order = order
   138  }
   139  
   140  func (s *sort_TYPE_DIR_HANDLES_NULLSOp) sort(ctx context.Context) {
   141  	n := execgen.LEN(s.sortCol)
   142  	s.quickSort(ctx, 0, n, maxDepth(n))
   143  }
   144  
   145  func (s *sort_TYPE_DIR_HANDLES_NULLSOp) sortPartitions(ctx context.Context, partitions []int) {
   146  	if len(partitions) < 1 {
   147  		colexecerror.InternalError(fmt.Sprintf("invalid partitions list %v", partitions))
   148  	}
   149  	order := s.order
   150  	for i, partitionStart := range partitions {
   151  		var partitionEnd int
   152  		if i == len(partitions)-1 {
   153  			partitionEnd = len(order)
   154  		} else {
   155  			partitionEnd = partitions[i+1]
   156  		}
   157  		s.order = order[partitionStart:partitionEnd]
   158  		n := partitionEnd - partitionStart
   159  		s.quickSort(ctx, 0, n, maxDepth(n))
   160  	}
   161  }
   162  
   163  func (s *sort_TYPE_DIR_HANDLES_NULLSOp) Less(i, j int) bool {
   164  	// {{if $nulls}}
   165  	n1 := s.nulls.MaybeHasNulls() && s.nulls.NullAt(s.order[i])
   166  	n2 := s.nulls.MaybeHasNulls() && s.nulls.NullAt(s.order[j])
   167  	// {{if eq $dir "Asc"}}
   168  	// If ascending, nulls always sort first, so we encode that logic here.
   169  	if n1 && n2 {
   170  		return false
   171  	} else if n1 {
   172  		return true
   173  	} else if n2 {
   174  		return false
   175  	}
   176  	// {{else if eq $dir "Desc"}}
   177  	// If descending, nulls always sort last, so we encode that logic here.
   178  	if n1 && n2 {
   179  		return false
   180  	} else if n1 {
   181  		return false
   182  	} else if n2 {
   183  		return true
   184  	}
   185  	// {{end}}
   186  	// {{end}}
   187  	var lt bool
   188  	// We always indirect via the order vector.
   189  	arg1 := execgen.UNSAFEGET(s.sortCol, s.order[i])
   190  	arg2 := execgen.UNSAFEGET(s.sortCol, s.order[j])
   191  	_ASSIGN_LT(lt, arg1, arg2, _, s.sortCol, s.sortCol)
   192  	return lt
   193  }
   194  
   195  func (s *sort_TYPE_DIR_HANDLES_NULLSOp) Swap(i, j int) {
   196  	// We don't physically swap the column - we merely edit the order vector.
   197  	s.order[i], s.order[j] = s.order[j], s.order[i]
   198  }
   199  
   200  func (s *sort_TYPE_DIR_HANDLES_NULLSOp) Len() int {
   201  	return len(s.order)
   202  }
   203  
   204  // {{end}}
   205  // {{end}}
   206  // {{end}}
   207  // {{end}}