github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/colexec/any_not_null_agg_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 any_not_null_agg.eg.go. It's formatted
    15  // in a special way, so it's both valid Go and a valid text/template input.
    16  // This 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/colmem"
    29  	"github.com/cockroachdb/cockroach/pkg/sql/types"
    30  	"github.com/cockroachdb/errors"
    31  )
    32  
    33  // Remove unused warning.
    34  var _ = execgen.UNSAFEGET
    35  
    36  // {{/*
    37  
    38  // Declarations to make the template compile properly.
    39  
    40  // _GOTYPESLICE is the template variable.
    41  type _GOTYPESLICE interface{}
    42  
    43  // _CANONICAL_TYPE_FAMILY is the template variable.
    44  const _CANONICAL_TYPE_FAMILY = types.UnknownFamily
    45  
    46  // _TYPE_WIDTH is the template variable.
    47  const _TYPE_WIDTH = 0
    48  
    49  // */}}
    50  
    51  func newAnyNotNullAggAlloc(
    52  	allocator *colmem.Allocator, t *types.T, allocSize int64,
    53  ) (aggregateFuncAlloc, error) {
    54  	switch typeconv.TypeFamilyToCanonicalTypeFamily(t.Family()) {
    55  	// {{range .}}
    56  	case _CANONICAL_TYPE_FAMILY:
    57  		switch t.Width() {
    58  		// {{range .WidthOverloads}}
    59  		case _TYPE_WIDTH:
    60  			return &anyNotNull_TYPEAggAlloc{allocator: allocator, allocSize: allocSize}, nil
    61  			// {{end}}
    62  		}
    63  		// {{end}}
    64  	}
    65  	return nil, errors.Errorf("unsupported any not null agg type %s", t.Name())
    66  }
    67  
    68  // {{range .}}
    69  // {{range .WidthOverloads}}
    70  
    71  // anyNotNull_TYPEAgg implements the ANY_NOT_NULL aggregate, returning the
    72  // first non-null value in the input column.
    73  type anyNotNull_TYPEAgg struct {
    74  	allocator                   *colmem.Allocator
    75  	groups                      []bool
    76  	vec                         coldata.Vec
    77  	col                         _GOTYPESLICE
    78  	nulls                       *coldata.Nulls
    79  	curIdx                      int
    80  	curAgg                      _GOTYPE
    81  	foundNonNullForCurrentGroup bool
    82  }
    83  
    84  var _ aggregateFunc = &anyNotNull_TYPEAgg{}
    85  
    86  const sizeOfAnyNotNull_TYPEAgg = int64(unsafe.Sizeof(anyNotNull_TYPEAgg{}))
    87  
    88  func (a *anyNotNull_TYPEAgg) Init(groups []bool, vec coldata.Vec) {
    89  	a.groups = groups
    90  	a.vec = vec
    91  	a.col = vec.TemplateType()
    92  	a.nulls = vec.Nulls()
    93  	a.Reset()
    94  }
    95  
    96  func (a *anyNotNull_TYPEAgg) Reset() {
    97  	a.curIdx = -1
    98  	a.foundNonNullForCurrentGroup = false
    99  	a.nulls.UnsetNulls()
   100  }
   101  
   102  func (a *anyNotNull_TYPEAgg) CurrentOutputIndex() int {
   103  	return a.curIdx
   104  }
   105  
   106  func (a *anyNotNull_TYPEAgg) SetOutputIndex(idx int) {
   107  	if a.curIdx != -1 {
   108  		a.curIdx = idx
   109  		a.nulls.UnsetNullsAfter(idx + 1)
   110  	}
   111  }
   112  
   113  func (a *anyNotNull_TYPEAgg) Compute(b coldata.Batch, inputIdxs []uint32) {
   114  	inputLen := b.Length()
   115  	vec, sel := b.ColVec(int(inputIdxs[0])), b.Selection()
   116  	col, nulls := vec.TemplateType(), vec.Nulls()
   117  
   118  	a.allocator.PerformOperation(
   119  		[]coldata.Vec{a.vec},
   120  		func() {
   121  			if nulls.MaybeHasNulls() {
   122  				if sel != nil {
   123  					sel = sel[:inputLen]
   124  					for _, i := range sel {
   125  						_FIND_ANY_NOT_NULL(a, nulls, i, true)
   126  					}
   127  				} else {
   128  					col = execgen.SLICE(col, 0, inputLen)
   129  					for execgen.RANGE(i, col, 0, inputLen) {
   130  						_FIND_ANY_NOT_NULL(a, nulls, i, true)
   131  					}
   132  				}
   133  			} else {
   134  				if sel != nil {
   135  					sel = sel[:inputLen]
   136  					for _, i := range sel {
   137  						_FIND_ANY_NOT_NULL(a, nulls, i, false)
   138  					}
   139  				} else {
   140  					col = execgen.SLICE(col, 0, inputLen)
   141  					for execgen.RANGE(i, col, 0, inputLen) {
   142  						_FIND_ANY_NOT_NULL(a, nulls, i, false)
   143  					}
   144  				}
   145  			}
   146  		},
   147  	)
   148  }
   149  
   150  func (a *anyNotNull_TYPEAgg) Flush() {
   151  	// If we haven't found any non-nulls for this group so far, the output for
   152  	// this group should be null.
   153  	if !a.foundNonNullForCurrentGroup {
   154  		a.nulls.SetNull(a.curIdx)
   155  	} else {
   156  		execgen.SET(a.col, a.curIdx, a.curAgg)
   157  	}
   158  	a.curIdx++
   159  }
   160  
   161  func (a *anyNotNull_TYPEAgg) HandleEmptyInputScalar() {
   162  	a.nulls.SetNull(0)
   163  }
   164  
   165  type anyNotNull_TYPEAggAlloc struct {
   166  	allocator *colmem.Allocator
   167  	allocSize int64
   168  	aggFuncs  []anyNotNull_TYPEAgg
   169  }
   170  
   171  var _ aggregateFuncAlloc = &anyNotNull_TYPEAggAlloc{}
   172  
   173  func (a *anyNotNull_TYPEAggAlloc) newAggFunc() aggregateFunc {
   174  	if len(a.aggFuncs) == 0 {
   175  		a.allocator.AdjustMemoryUsage(sizeOfAnyNotNull_TYPEAgg * a.allocSize)
   176  		a.aggFuncs = make([]anyNotNull_TYPEAgg, a.allocSize)
   177  	}
   178  	f := &a.aggFuncs[0]
   179  	f.allocator = a.allocator
   180  	a.aggFuncs = a.aggFuncs[1:]
   181  	return f
   182  }
   183  
   184  // {{end}}
   185  // {{end}}
   186  
   187  // {{/*
   188  // _FIND_ANY_NOT_NULL finds a non-null value for the group that contains the ith
   189  // row. If a non-null value was already found, then it does nothing. If this is
   190  // the first row of a new group, and no non-nulls have been found for the
   191  // current group, then the output for the current group is set to null.
   192  func _FIND_ANY_NOT_NULL(a *anyNotNull_TYPEAgg, nulls *coldata.Nulls, i int, _HAS_NULLS bool) { // */}}
   193  	// {{define "findAnyNotNull" -}}
   194  
   195  	if a.groups[i] {
   196  		// The `a.curIdx` check is necessary because for the first
   197  		// group in the result set there is no "current group."
   198  		if a.curIdx >= 0 {
   199  			// If this is a new group, check if any non-nulls have been found for the
   200  			// current group.
   201  			if !a.foundNonNullForCurrentGroup {
   202  				a.nulls.SetNull(a.curIdx)
   203  			} else {
   204  				// {{with .Global}}
   205  				execgen.SET(a.col, a.curIdx, a.curAgg)
   206  				// {{end}}
   207  			}
   208  		}
   209  		a.curIdx++
   210  		a.foundNonNullForCurrentGroup = false
   211  	}
   212  	var isNull bool
   213  	// {{if .HasNulls}}
   214  	isNull = nulls.NullAt(i)
   215  	// {{else}}
   216  	isNull = false
   217  	// {{end}}
   218  	if !a.foundNonNullForCurrentGroup && !isNull {
   219  		// If we haven't seen any non-nulls for the current group yet, and the
   220  		// current value is non-null, then we can pick the current value to be the
   221  		// output.
   222  		// {{with .Global}}
   223  		val := execgen.UNSAFEGET(col, i)
   224  		execgen.COPYVAL(a.curAgg, val)
   225  		// {{end}}
   226  		a.foundNonNullForCurrentGroup = true
   227  	}
   228  	// {{end}}
   229  
   230  	// {{/*
   231  } // */}}