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

     1  // Copyright 2019 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 min_max_agg.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  	"unsafe"
    24  
    25  	"github.com/cockroachdb/cockroach/pkg/col/coldata"
    26  	"github.com/cockroachdb/cockroach/pkg/col/typeconv"
    27  	"github.com/cockroachdb/cockroach/pkg/sql/colexec/execgen"
    28  	"github.com/cockroachdb/cockroach/pkg/sql/colexecbase/colexecerror"
    29  	"github.com/cockroachdb/cockroach/pkg/sql/colmem"
    30  	"github.com/cockroachdb/cockroach/pkg/sql/types"
    31  	"github.com/cockroachdb/errors"
    32  )
    33  
    34  // Remove unused warning.
    35  var _ = execgen.UNSAFEGET
    36  
    37  // Remove unused warning.
    38  var _ = colexecerror.InternalError
    39  
    40  // {{/*
    41  // Declarations to make the template compile properly.
    42  
    43  // _GOTYPESLICE is the template variable.
    44  type _GOTYPESLICE interface{}
    45  
    46  // _CANONICAL_TYPE_FAMILY is the template variable.
    47  const _CANONICAL_TYPE_FAMILY = types.UnknownFamily
    48  
    49  // _TYPE_WIDTH is the template variable.
    50  const _TYPE_WIDTH = 0
    51  
    52  // _ASSIGN_CMP is the template function for assigning true to the first input
    53  // if the second input compares successfully to the third input. The comparison
    54  // operator is tree.LT for MIN and is tree.GT for MAX.
    55  func _ASSIGN_CMP(_, _, _, _, _, _ string) bool {
    56  	colexecerror.InternalError("")
    57  }
    58  
    59  // */}}
    60  
    61  // {{range .}} {{/* for each aggregation (min and max) */}}
    62  
    63  // {{/* Capture the aggregation name so we can use it in the inner loop. */}}
    64  // {{$agg := .AggNameLower}}
    65  
    66  func new_AGG_TITLEAggAlloc(
    67  	allocator *colmem.Allocator, t *types.T, allocSize int64,
    68  ) (aggregateFuncAlloc, error) {
    69  	switch typeconv.TypeFamilyToCanonicalTypeFamily(t.Family()) {
    70  	// {{range .Overloads}}
    71  	case _CANONICAL_TYPE_FAMILY:
    72  		switch t.Width() {
    73  		// {{range .WidthOverloads}}
    74  		case _TYPE_WIDTH:
    75  			return &_AGG_TYPEAggAlloc{allocator: allocator, allocSize: allocSize}, nil
    76  			// {{end}}
    77  		}
    78  		// {{end}}
    79  	}
    80  	return nil, errors.Errorf("unsupported _AGG agg type %s", t.Name())
    81  }
    82  
    83  // {{range .Overloads}}
    84  // {{range .WidthOverloads}}
    85  
    86  type _AGG_TYPEAgg struct {
    87  	allocator *colmem.Allocator
    88  	groups    []bool
    89  	curIdx    int
    90  	// curAgg holds the running min/max, so we can index into the slice once per
    91  	// group, instead of on each iteration.
    92  	// NOTE: if foundNonNullForCurrentGroup is false, curAgg is undefined.
    93  	curAgg _GOTYPE
    94  	// col points to the output vector we are updating.
    95  	col _GOTYPESLICE
    96  	// vec is the same as col before conversion from coldata.Vec.
    97  	vec coldata.Vec
    98  	// nulls points to the output null vector that we are updating.
    99  	nulls *coldata.Nulls
   100  	// foundNonNullForCurrentGroup tracks if we have seen any non-null values
   101  	// for the group that is currently being aggregated.
   102  	foundNonNullForCurrentGroup bool
   103  }
   104  
   105  var _ aggregateFunc = &_AGG_TYPEAgg{}
   106  
   107  const sizeOf_AGG_TYPEAgg = int64(unsafe.Sizeof(_AGG_TYPEAgg{}))
   108  
   109  func (a *_AGG_TYPEAgg) Init(groups []bool, v coldata.Vec) {
   110  	a.groups = groups
   111  	a.vec = v
   112  	a.col = v._TYPE()
   113  	a.nulls = v.Nulls()
   114  	a.Reset()
   115  }
   116  
   117  func (a *_AGG_TYPEAgg) Reset() {
   118  	a.curIdx = -1
   119  	a.foundNonNullForCurrentGroup = false
   120  	a.nulls.UnsetNulls()
   121  }
   122  
   123  func (a *_AGG_TYPEAgg) CurrentOutputIndex() int {
   124  	return a.curIdx
   125  }
   126  
   127  func (a *_AGG_TYPEAgg) SetOutputIndex(idx int) {
   128  	if a.curIdx != -1 {
   129  		a.curIdx = idx
   130  		a.nulls.UnsetNullsAfter(idx + 1)
   131  	}
   132  }
   133  
   134  func (a *_AGG_TYPEAgg) Compute(b coldata.Batch, inputIdxs []uint32) {
   135  	inputLen := b.Length()
   136  	vec, sel := b.ColVec(int(inputIdxs[0])), b.Selection()
   137  	col, nulls := vec._TYPE(), vec.Nulls()
   138  	a.allocator.PerformOperation(
   139  		[]coldata.Vec{a.vec},
   140  		func() {
   141  			if nulls.MaybeHasNulls() {
   142  				if sel != nil {
   143  					sel = sel[:inputLen]
   144  					for _, i := range sel {
   145  						_ACCUMULATE_MINMAX(a, nulls, i, true)
   146  					}
   147  				} else {
   148  					col = execgen.SLICE(col, 0, inputLen)
   149  					for execgen.RANGE(i, col, 0, inputLen) {
   150  						_ACCUMULATE_MINMAX(a, nulls, i, true)
   151  					}
   152  				}
   153  			} else {
   154  				if sel != nil {
   155  					sel = sel[:inputLen]
   156  					for _, i := range sel {
   157  						_ACCUMULATE_MINMAX(a, nulls, i, false)
   158  					}
   159  				} else {
   160  					col = execgen.SLICE(col, 0, inputLen)
   161  					for execgen.RANGE(i, col, 0, inputLen) {
   162  						_ACCUMULATE_MINMAX(a, nulls, i, false)
   163  					}
   164  				}
   165  			}
   166  		},
   167  	)
   168  }
   169  
   170  func (a *_AGG_TYPEAgg) Flush() {
   171  	// The aggregation is finished. Flush the last value. If we haven't found
   172  	// any non-nulls for this group so far, the output for this group should
   173  	// be null.
   174  	if !a.foundNonNullForCurrentGroup {
   175  		a.nulls.SetNull(a.curIdx)
   176  	} else {
   177  		execgen.SET(a.col, a.curIdx, a.curAgg)
   178  	}
   179  	a.curIdx++
   180  }
   181  
   182  func (a *_AGG_TYPEAgg) HandleEmptyInputScalar() {
   183  	a.nulls.SetNull(0)
   184  }
   185  
   186  type _AGG_TYPEAggAlloc struct {
   187  	allocator *colmem.Allocator
   188  	allocSize int64
   189  	aggFuncs  []_AGG_TYPEAgg
   190  }
   191  
   192  var _ aggregateFuncAlloc = &_AGG_TYPEAggAlloc{}
   193  
   194  func (a *_AGG_TYPEAggAlloc) newAggFunc() aggregateFunc {
   195  	if len(a.aggFuncs) == 0 {
   196  		a.allocator.AdjustMemoryUsage(sizeOf_AGG_TYPEAgg * a.allocSize)
   197  		a.aggFuncs = make([]_AGG_TYPEAgg, a.allocSize)
   198  	}
   199  	f := &a.aggFuncs[0]
   200  	f.allocator = a.allocator
   201  	a.aggFuncs = a.aggFuncs[1:]
   202  	return f
   203  }
   204  
   205  // {{end}}
   206  // {{end}}
   207  // {{end}}
   208  
   209  // {{/*
   210  // _ACCUMULATE_MINMAX sets the output for the current group to be the value of
   211  // the ith row if it is smaller/larger than the current result. If this is the
   212  // first row of a new group, and no non-nulls have been found for the current
   213  // group, then the output for the current group is set to null.
   214  func _ACCUMULATE_MINMAX(a *_AGG_TYPEAgg, nulls *coldata.Nulls, i int, _HAS_NULLS bool) { // */}}
   215  
   216  	// {{define "accumulateMinMax"}}
   217  	if a.groups[i] {
   218  		// If we encounter a new group, and we haven't found any non-nulls for the
   219  		// current group, the output for this group should be null. If a.curIdx is
   220  		// negative, it means that this is the first group.
   221  		if a.curIdx >= 0 {
   222  			if !a.foundNonNullForCurrentGroup {
   223  				a.nulls.SetNull(a.curIdx)
   224  			} else {
   225  				// {{with .Global}}
   226  				execgen.SET(a.col, a.curIdx, a.curAgg)
   227  				// {{end}}
   228  			}
   229  		}
   230  		a.curIdx++
   231  		a.foundNonNullForCurrentGroup = false
   232  	}
   233  	var isNull bool
   234  	// {{if .HasNulls}}
   235  	isNull = nulls.NullAt(i)
   236  	// {{else}}
   237  	isNull = false
   238  	// {{end}}
   239  	// {{with .Global}}
   240  	if !isNull {
   241  		if !a.foundNonNullForCurrentGroup {
   242  			val := execgen.UNSAFEGET(col, i)
   243  			execgen.COPYVAL(a.curAgg, val)
   244  			a.foundNonNullForCurrentGroup = true
   245  		} else {
   246  			var cmp bool
   247  			candidate := execgen.UNSAFEGET(col, i)
   248  			_ASSIGN_CMP(cmp, candidate, a.curAgg, _, col, _)
   249  			if cmp {
   250  				execgen.COPYVAL(a.curAgg, candidate)
   251  			}
   252  		}
   253  	}
   254  	// {{end}}
   255  	// {{end}}
   256  
   257  	// {{/*
   258  } // */}}