github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/colexec/window_peer_grouper_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 window_peer_grouper.eg.go. It's
    15  // formatted in a special way, so it's both valid Go and a valid text/template
    16  // input. This permits editing this file with editor support.
    17  //
    18  // */}}
    19  
    20  package colexec
    21  
    22  import (
    23  	"context"
    24  
    25  	"github.com/cockroachdb/cockroach/pkg/col/coldata"
    26  	"github.com/cockroachdb/cockroach/pkg/sql/colexecbase"
    27  	"github.com/cockroachdb/cockroach/pkg/sql/colmem"
    28  	"github.com/cockroachdb/cockroach/pkg/sql/execinfrapb"
    29  	"github.com/cockroachdb/cockroach/pkg/sql/types"
    30  )
    31  
    32  // NewWindowPeerGrouper creates a new Operator that puts 'true' in
    33  // outputColIdx'th column (which is appended if needed) for every tuple that is
    34  // the first within its peer group. Peers are tuples that belong to the same
    35  // partition and are equal on the ordering columns. If orderingCols is empty,
    36  // then all tuples within the partition are peers.
    37  // - partitionColIdx, if not columnOmitted, *must* specify the column in which
    38  //   'true' indicates the start of a new partition.
    39  // NOTE: the input *must* already be ordered on ordCols.
    40  func NewWindowPeerGrouper(
    41  	allocator *colmem.Allocator,
    42  	input colexecbase.Operator,
    43  	typs []*types.T,
    44  	orderingCols []execinfrapb.Ordering_Column,
    45  	partitionColIdx int,
    46  	outputColIdx int,
    47  ) (op colexecbase.Operator, err error) {
    48  	allPeers := len(orderingCols) == 0
    49  	var distinctCol []bool
    50  	if !allPeers {
    51  		orderIdxs := make([]uint32, len(orderingCols))
    52  		for i, ordCol := range orderingCols {
    53  			orderIdxs[i] = ordCol.ColIdx
    54  		}
    55  		input, distinctCol, err = OrderedDistinctColsToOperators(
    56  			input, orderIdxs, typs,
    57  		)
    58  		if err != nil {
    59  			return nil, err
    60  		}
    61  	}
    62  	input = newVectorTypeEnforcer(allocator, input, types.Bool, outputColIdx)
    63  	initFields := windowPeerGrouperInitFields{
    64  		OneInputNode:    NewOneInputNode(input),
    65  		allocator:       allocator,
    66  		partitionColIdx: partitionColIdx,
    67  		distinctCol:     distinctCol,
    68  		outputColIdx:    outputColIdx,
    69  	}
    70  	if allPeers {
    71  		if partitionColIdx != columnOmitted {
    72  			return &windowPeerGrouperAllPeersWithPartitionOp{
    73  				windowPeerGrouperInitFields: initFields,
    74  			}, nil
    75  		}
    76  		return &windowPeerGrouperAllPeersNoPartitionOp{
    77  			windowPeerGrouperInitFields: initFields,
    78  		}, nil
    79  	}
    80  	if partitionColIdx != columnOmitted {
    81  		return &windowPeerGrouperWithPartitionOp{
    82  			windowPeerGrouperInitFields: initFields,
    83  		}, nil
    84  	}
    85  	return &windowPeerGrouperNoPartitionOp{
    86  		windowPeerGrouperInitFields: initFields,
    87  	}, nil
    88  }
    89  
    90  type windowPeerGrouperInitFields struct {
    91  	OneInputNode
    92  
    93  	allocator       *colmem.Allocator
    94  	partitionColIdx int
    95  	// distinctCol is the output column of the chain of ordered distinct
    96  	// operators in which 'true' will indicate that a new peer group begins with
    97  	// the corresponding tuple.
    98  	distinctCol  []bool
    99  	outputColIdx int
   100  }
   101  
   102  // {{range .}}
   103  
   104  type _PEER_GROUPER_STRINGOp struct {
   105  	windowPeerGrouperInitFields
   106  	// {{if and .AllPeers (not .HasPartition)}}
   107  	seenFirstTuple bool
   108  	// {{end}}
   109  }
   110  
   111  var _ colexecbase.Operator = &_PEER_GROUPER_STRINGOp{}
   112  
   113  func (p *_PEER_GROUPER_STRINGOp) Init() {
   114  	p.input.Init()
   115  }
   116  
   117  func (p *_PEER_GROUPER_STRINGOp) Next(ctx context.Context) coldata.Batch {
   118  	b := p.input.Next(ctx)
   119  	n := b.Length()
   120  	if n == 0 {
   121  		return b
   122  	}
   123  	// {{if .HasPartition}}
   124  	partitionCol := b.ColVec(p.partitionColIdx).Bool()
   125  	// {{end}}
   126  	sel := b.Selection()
   127  	peersVec := b.ColVec(p.outputColIdx)
   128  	if peersVec.MaybeHasNulls() {
   129  		// We need to make sure that there are no left over null values in the
   130  		// output vector.
   131  		peersVec.Nulls().UnsetNulls()
   132  	}
   133  	peersCol := peersVec.Bool()
   134  	if sel != nil {
   135  		for _, i := range sel[:n] {
   136  			// {{if .AllPeers}}
   137  			// {{if .HasPartition}}
   138  			// All tuples within the partition are peers, so we simply need to copy
   139  			// over partitionCol according to sel.
   140  			peersCol[i] = partitionCol[i]
   141  			// {{else}}
   142  			// There is only one partition and all tuples within it are peers, so we
   143  			// need to set 'true' to only the first tuple ever seen.
   144  			peersCol[i] = !p.seenFirstTuple
   145  			p.seenFirstTuple = true
   146  			// {{end}}
   147  			// {{else}}
   148  			// {{if .HasPartition}}
   149  			// The new peer group begins either when a new partition begins (in which
   150  			// case partitionCol[i] is 'true') or when i'th tuple is different from
   151  			// i-1'th (in which case p.distinctCol[i] is 'true').
   152  			peersCol[i] = partitionCol[i] || p.distinctCol[i]
   153  			// {{else}}
   154  			// The new peer group begins when i'th tuple is different from i-1'th (in
   155  			// which case p.distinctCol[i] is 'true').
   156  			peersCol[i] = p.distinctCol[i]
   157  			// {{end}}
   158  			// {{end}}
   159  		}
   160  	} else {
   161  		// {{if .AllPeers}}
   162  		// {{if .HasPartition}}
   163  		// All tuples within the partition are peers, so we simply need to copy
   164  		// over partitionCol.
   165  		copy(peersCol[:n], partitionCol[:n])
   166  		// {{else}}
   167  		// There is only one partition and all tuples within it are peers, so we
   168  		// need to set 'true' to only the first tuple ever seen.
   169  		copy(peersCol[:n], zeroBoolColumn[:n])
   170  		peersCol[0] = !p.seenFirstTuple
   171  		p.seenFirstTuple = true
   172  		// {{end}}
   173  		// {{else}}
   174  		// {{if .HasPartition}}
   175  		// The new peer group begins either when a new partition begins (in which
   176  		// case partitionCol[i] is 'true') or when i'th tuple is different from
   177  		// i-1'th (in which case p.distinctCol[i] is 'true').
   178  		for i := range peersCol[:n] {
   179  			peersCol[i] = partitionCol[i] || p.distinctCol[i]
   180  		}
   181  		// {{else}}
   182  		// The new peer group begins when i'th tuple is different from i-1'th (in
   183  		// which case p.distinctCol[i] is 'true'), so we simply need to copy over
   184  		// p.distinctCol.
   185  		copy(peersCol[:n], p.distinctCol[:n])
   186  		// {{end}}
   187  		// {{end}}
   188  	}
   189  	return b
   190  }
   191  
   192  // {{end}}