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

     1  // Copyright 2020 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 substring.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/sql/colexecbase"
    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  // {{/*
    35  
    36  // _START_WIDTH is the template variable.
    37  const _START_WIDTH = 0
    38  
    39  // _LENGTH_WIDTH is the template variable.
    40  const _LENGTH_WIDTH = 0
    41  
    42  // */}}
    43  
    44  func newSubstringOperator(
    45  	allocator *colmem.Allocator,
    46  	typs []*types.T,
    47  	argumentCols []int,
    48  	outputIdx int,
    49  	input colexecbase.Operator,
    50  ) colexecbase.Operator {
    51  	startType := typs[argumentCols[1]]
    52  	lengthType := typs[argumentCols[2]]
    53  	base := substringFunctionBase{
    54  		OneInputNode: NewOneInputNode(input),
    55  		allocator:    allocator,
    56  		argumentCols: argumentCols,
    57  		outputIdx:    outputIdx,
    58  	}
    59  	if startType.Family() != types.IntFamily {
    60  		colexecerror.InternalError(fmt.Sprintf("non-int start argument type %s", startType))
    61  	}
    62  	if lengthType.Family() != types.IntFamily {
    63  		colexecerror.InternalError(fmt.Sprintf("non-int length argument type %s", lengthType))
    64  	}
    65  	switch startType.Width() {
    66  	// {{range $startWidth, $lengthWidths := .}}
    67  	case _START_WIDTH:
    68  		switch lengthType.Width() {
    69  		// {{range $lengthWidth := $lengthWidths}}
    70  		case _LENGTH_WIDTH:
    71  			return &substring_StartType_LengthTypeOperator{base}
    72  			// {{end}}
    73  		}
    74  		// {{end}}
    75  	}
    76  	colexecerror.InternalError(errors.Errorf("unsupported substring argument types: %s %s", startType, lengthType))
    77  	// This code is unreachable, but the compiler cannot infer that.
    78  	return nil
    79  }
    80  
    81  type substringFunctionBase struct {
    82  	OneInputNode
    83  	allocator    *colmem.Allocator
    84  	argumentCols []int
    85  	outputIdx    int
    86  }
    87  
    88  func (s *substringFunctionBase) Init() {
    89  	s.input.Init()
    90  }
    91  
    92  // {{range $startWidth, $lengthWidths := .}}
    93  // {{range $lengthWidth := $lengthWidths}}
    94  
    95  type substring_StartType_LengthTypeOperator struct {
    96  	substringFunctionBase
    97  }
    98  
    99  var _ colexecbase.Operator = &substring_StartType_LengthTypeOperator{}
   100  
   101  func (s *substring_StartType_LengthTypeOperator) Next(ctx context.Context) coldata.Batch {
   102  	batch := s.input.Next(ctx)
   103  	n := batch.Length()
   104  	if n == 0 {
   105  		return coldata.ZeroBatch
   106  	}
   107  
   108  	sel := batch.Selection()
   109  	runeVec := batch.ColVec(s.argumentCols[0]).Bytes()
   110  	startVec := batch.ColVec(s.argumentCols[1])._StartType()
   111  	lengthVec := batch.ColVec(s.argumentCols[2])._LengthType()
   112  	outputVec := batch.ColVec(s.outputIdx)
   113  	if outputVec.MaybeHasNulls() {
   114  		// We need to make sure that there are no left over null values in the
   115  		// output vector.
   116  		outputVec.Nulls().UnsetNulls()
   117  	}
   118  	outputCol := outputVec.Bytes()
   119  	s.allocator.PerformOperation(
   120  		[]coldata.Vec{outputVec},
   121  		func() {
   122  			for i := 0; i < n; i++ {
   123  				rowIdx := i
   124  				if sel != nil {
   125  					rowIdx = sel[i]
   126  				}
   127  
   128  				// The substring operator does not support nulls. If any of the arguments
   129  				// are NULL, we output NULL.
   130  				isNull := false
   131  				for _, col := range s.argumentCols {
   132  					if batch.ColVec(col).Nulls().NullAt(rowIdx) {
   133  						isNull = true
   134  						break
   135  					}
   136  				}
   137  				if isNull {
   138  					batch.ColVec(s.outputIdx).Nulls().SetNull(rowIdx)
   139  					continue
   140  				}
   141  
   142  				runes := runeVec.Get(rowIdx)
   143  				// Substring start is 1 indexed.
   144  				start := int(startVec[rowIdx]) - 1
   145  				length := int(lengthVec[rowIdx])
   146  				if length < 0 {
   147  					colexecerror.ExpectedError(errors.Errorf("negative substring length %d not allowed", length))
   148  				}
   149  
   150  				end := start + length
   151  				// Check for integer overflow.
   152  				if end < start {
   153  					end = len(runes)
   154  				} else if end < 0 {
   155  					end = 0
   156  				} else if end > len(runes) {
   157  					end = len(runes)
   158  				}
   159  
   160  				if start < 0 {
   161  					start = 0
   162  				} else if start > len(runes) {
   163  					start = len(runes)
   164  				}
   165  				outputCol.Set(rowIdx, runes[start:end])
   166  			}
   167  		},
   168  	)
   169  	// Although we didn't change the length of the batch, it is necessary to set
   170  	// the length anyway (this helps maintaining the invariant of flat bytes).
   171  	batch.SetLength(n)
   172  	return batch
   173  }
   174  
   175  // {{end}}
   176  // {{end}}