github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/rowexec/project_set.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  package rowexec
    12  
    13  import (
    14  	"context"
    15  	"fmt"
    16  
    17  	"github.com/cockroachdb/cockroach/pkg/sql/execinfra"
    18  	"github.com/cockroachdb/cockroach/pkg/sql/execinfrapb"
    19  	"github.com/cockroachdb/cockroach/pkg/sql/sem/builtins"
    20  	"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
    21  	"github.com/cockroachdb/cockroach/pkg/sql/sqlbase"
    22  )
    23  
    24  // projectSetProcessor is the physical processor implementation of
    25  // projectSetNode.
    26  type projectSetProcessor struct {
    27  	execinfra.ProcessorBase
    28  
    29  	input execinfra.RowSource
    30  	spec  *execinfrapb.ProjectSetSpec
    31  
    32  	// exprHelpers are the constant-folded, type checked expressions specified
    33  	// in the ROWS FROM syntax. This can contain many kinds of expressions
    34  	// (anything that is "function-like" including COALESCE, NULLIF) not just
    35  	// SRFs.
    36  	exprHelpers []*execinfra.ExprHelper
    37  
    38  	// funcs contains a valid pointer to a SRF FuncExpr for every entry
    39  	// in `exprHelpers` that is actually a SRF function application.
    40  	// The size of the slice is the same as `exprHelpers` though.
    41  	funcs []*tree.FuncExpr
    42  
    43  	// inputRowReady is set when there was a row of input data available
    44  	// from the source.
    45  	inputRowReady bool
    46  
    47  	// RowBuffer will contain the current row of results.
    48  	rowBuffer sqlbase.EncDatumRow
    49  
    50  	// gens contains the current "active" ValueGenerators for each entry
    51  	// in `funcs`. They are initialized anew for every new row in the source.
    52  	gens []tree.ValueGenerator
    53  
    54  	// done indicates for each `Expr` whether the values produced by
    55  	// either the SRF or the scalar expressions are fully consumed and
    56  	// thus also whether NULLs should be emitted instead.
    57  	done []bool
    58  
    59  	// emitCount is used to track the number of rows that have been
    60  	// emitted from Next().
    61  	emitCount int64
    62  }
    63  
    64  var _ execinfra.Processor = &projectSetProcessor{}
    65  var _ execinfra.RowSource = &projectSetProcessor{}
    66  var _ execinfra.OpNode = &projectSetProcessor{}
    67  
    68  const projectSetProcName = "projectSet"
    69  
    70  func newProjectSetProcessor(
    71  	flowCtx *execinfra.FlowCtx,
    72  	processorID int32,
    73  	spec *execinfrapb.ProjectSetSpec,
    74  	input execinfra.RowSource,
    75  	post *execinfrapb.PostProcessSpec,
    76  	output execinfra.RowReceiver,
    77  ) (*projectSetProcessor, error) {
    78  	outputTypes := append(input.OutputTypes(), spec.GeneratedColumns...)
    79  	ps := &projectSetProcessor{
    80  		input:       input,
    81  		spec:        spec,
    82  		exprHelpers: make([]*execinfra.ExprHelper, len(spec.Exprs)),
    83  		funcs:       make([]*tree.FuncExpr, len(spec.Exprs)),
    84  		rowBuffer:   make(sqlbase.EncDatumRow, len(outputTypes)),
    85  		gens:        make([]tree.ValueGenerator, len(spec.Exprs)),
    86  		done:        make([]bool, len(spec.Exprs)),
    87  	}
    88  	if err := ps.Init(
    89  		ps,
    90  		post,
    91  		outputTypes,
    92  		flowCtx,
    93  		processorID,
    94  		output,
    95  		nil, /* memMonitor */
    96  		execinfra.ProcStateOpts{InputsToDrain: []execinfra.RowSource{ps.input}},
    97  	); err != nil {
    98  		return nil, err
    99  	}
   100  	return ps, nil
   101  }
   102  
   103  // Start is part of the RowSource interface.
   104  func (ps *projectSetProcessor) Start(ctx context.Context) context.Context {
   105  	ps.input.Start(ctx)
   106  	ctx = ps.StartInternal(ctx, projectSetProcName)
   107  
   108  	// Initialize exprHelpers.
   109  	for i, expr := range ps.spec.Exprs {
   110  		var helper execinfra.ExprHelper
   111  		err := helper.Init(expr, ps.input.OutputTypes(), ps.EvalCtx)
   112  		if err != nil {
   113  			ps.MoveToDraining(err)
   114  			return ctx
   115  		}
   116  		if tFunc, ok := helper.Expr.(*tree.FuncExpr); ok && tFunc.IsGeneratorApplication() {
   117  			// Expr is a set-generating function.
   118  			ps.funcs[i] = tFunc
   119  		}
   120  		ps.exprHelpers[i] = &helper
   121  	}
   122  	return ctx
   123  }
   124  
   125  // nextInputRow returns the next row or metadata from ps.input. It also
   126  // initializes the value generators for that row.
   127  func (ps *projectSetProcessor) nextInputRow() (
   128  	sqlbase.EncDatumRow,
   129  	*execinfrapb.ProducerMetadata,
   130  	error,
   131  ) {
   132  	row, meta := ps.input.Next()
   133  	if row == nil {
   134  		return nil, meta, nil
   135  	}
   136  
   137  	// Initialize a round of SRF generators or scalar values.
   138  	for i := range ps.exprHelpers {
   139  		if fn := ps.funcs[i]; fn != nil {
   140  			// A set-generating function. Prepare its ValueGenerator.
   141  
   142  			// Set ExprHelper.row so that we can use it as an IndexedVarContainer.
   143  			ps.exprHelpers[i].Row = row
   144  
   145  			ps.EvalCtx.IVarContainer = ps.exprHelpers[i]
   146  			gen, err := fn.EvalArgsAndGetGenerator(ps.EvalCtx)
   147  			if err != nil {
   148  				return nil, nil, err
   149  			}
   150  			if gen == nil {
   151  				gen = builtins.EmptyGenerator()
   152  			}
   153  			if err := gen.Start(ps.Ctx, ps.FlowCtx.Txn); err != nil {
   154  				return nil, nil, err
   155  			}
   156  			ps.gens[i] = gen
   157  		}
   158  		ps.done[i] = false
   159  	}
   160  
   161  	return row, nil, nil
   162  }
   163  
   164  // nextGeneratorValues populates the row buffer with the next set of generated
   165  // values. It returns true if any of the generators produce new values.
   166  func (ps *projectSetProcessor) nextGeneratorValues() (newValAvail bool, err error) {
   167  	colIdx := len(ps.input.OutputTypes())
   168  	for i := range ps.exprHelpers {
   169  		// Do we have a SRF?
   170  		if gen := ps.gens[i]; gen != nil {
   171  			// Yes. Is there still work to do for the current row?
   172  			numCols := int(ps.spec.NumColsPerGen[i])
   173  			if !ps.done[i] {
   174  				// Yes; check whether this source still has some values available.
   175  				hasVals, err := gen.Next(ps.Ctx)
   176  				if err != nil {
   177  					return false, err
   178  				}
   179  				if hasVals {
   180  					// This source has values, use them.
   181  					values, err := gen.Values()
   182  					if err != nil {
   183  						return false, err
   184  					}
   185  					for _, value := range values {
   186  						ps.rowBuffer[colIdx] = ps.toEncDatum(value, colIdx)
   187  						colIdx++
   188  					}
   189  					newValAvail = true
   190  				} else {
   191  					ps.done[i] = true
   192  					// No values left. Fill the buffer with NULLs for future results.
   193  					for j := 0; j < numCols; j++ {
   194  						ps.rowBuffer[colIdx] = ps.toEncDatum(tree.DNull, colIdx)
   195  						colIdx++
   196  					}
   197  				}
   198  			} else {
   199  				// Already done. Increment colIdx.
   200  				colIdx += numCols
   201  			}
   202  		} else {
   203  			// A simple scalar result.
   204  			// Do we still need to produce the scalar value? (first row)
   205  			if !ps.done[i] {
   206  				// Yes. Produce it once, then indicate it's "done".
   207  				value, err := ps.exprHelpers[i].Eval(ps.rowBuffer)
   208  				if err != nil {
   209  					return false, err
   210  				}
   211  				ps.rowBuffer[colIdx] = ps.toEncDatum(value, colIdx)
   212  				colIdx++
   213  				newValAvail = true
   214  				ps.done[i] = true
   215  			} else {
   216  				// Ensure that every row after the first returns a NULL value.
   217  				ps.rowBuffer[colIdx] = ps.toEncDatum(tree.DNull, colIdx)
   218  				colIdx++
   219  			}
   220  		}
   221  	}
   222  	return newValAvail, nil
   223  }
   224  
   225  // Next is part of the RowSource interface.
   226  func (ps *projectSetProcessor) Next() (sqlbase.EncDatumRow, *execinfrapb.ProducerMetadata) {
   227  	const cancelCheckCount = 10000
   228  
   229  	for ps.State == execinfra.StateRunning {
   230  
   231  		// Occasionally check for cancellation.
   232  		ps.emitCount++
   233  		if ps.emitCount%cancelCheckCount == 0 {
   234  			if err := ps.Ctx.Err(); err != nil {
   235  				ps.MoveToDraining(err)
   236  				return nil, ps.DrainHelper()
   237  			}
   238  		}
   239  
   240  		// Start of a new row of input?
   241  		if !ps.inputRowReady {
   242  			// Read the row from the source.
   243  			row, meta, err := ps.nextInputRow()
   244  			if meta != nil {
   245  				if meta.Err != nil {
   246  					ps.MoveToDraining(nil /* err */)
   247  				}
   248  				return nil, meta
   249  			}
   250  			if err != nil {
   251  				ps.MoveToDraining(err)
   252  				return nil, ps.DrainHelper()
   253  			}
   254  			if row == nil {
   255  				ps.MoveToDraining(nil /* err */)
   256  				return nil, ps.DrainHelper()
   257  			}
   258  
   259  			// Keep the values for later.
   260  			copy(ps.rowBuffer, row)
   261  			ps.inputRowReady = true
   262  		}
   263  
   264  		// Try to find some data on the generator side.
   265  		newValAvail, err := ps.nextGeneratorValues()
   266  		if err != nil {
   267  			ps.MoveToDraining(err)
   268  			return nil, ps.DrainHelper()
   269  		}
   270  		if newValAvail {
   271  			if outRow := ps.ProcessRowHelper(ps.rowBuffer); outRow != nil {
   272  				return outRow, nil
   273  			}
   274  		} else {
   275  			// The current batch of SRF values was exhausted. Advance
   276  			// to the next input row.
   277  			ps.inputRowReady = false
   278  		}
   279  	}
   280  	return nil, ps.DrainHelper()
   281  }
   282  
   283  func (ps *projectSetProcessor) toEncDatum(d tree.Datum, colIdx int) sqlbase.EncDatum {
   284  	generatedColIdx := colIdx - len(ps.input.OutputTypes())
   285  	ctyp := ps.spec.GeneratedColumns[generatedColIdx]
   286  	return sqlbase.DatumToEncDatum(ctyp, d)
   287  }
   288  
   289  // ConsumerClosed is part of the RowSource interface.
   290  func (ps *projectSetProcessor) ConsumerClosed() {
   291  	// The consumer is done, Next() will not be called again.
   292  	ps.InternalClose()
   293  }
   294  
   295  // ChildCount is part of the execinfra.OpNode interface.
   296  func (ps *projectSetProcessor) ChildCount(verbose bool) int {
   297  	if _, ok := ps.input.(execinfra.OpNode); ok {
   298  		return 1
   299  	}
   300  	return 0
   301  }
   302  
   303  // Child is part of the execinfra.OpNode interface.
   304  func (ps *projectSetProcessor) Child(nth int, verbose bool) execinfra.OpNode {
   305  	if nth == 0 {
   306  		if n, ok := ps.input.(execinfra.OpNode); ok {
   307  			return n
   308  		}
   309  		panic("input to projectSetProcessor is not an execinfra.OpNode")
   310  
   311  	}
   312  	panic(fmt.Sprintf("invalid index %d", nth))
   313  }