github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/rowexec/ordinality.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  package rowexec
    12  
    13  import (
    14  	"context"
    15  
    16  	"github.com/cockroachdb/cockroach/pkg/sql/execinfra"
    17  	"github.com/cockroachdb/cockroach/pkg/sql/execinfrapb"
    18  	"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
    19  	"github.com/cockroachdb/cockroach/pkg/sql/sqlbase"
    20  	"github.com/cockroachdb/cockroach/pkg/sql/types"
    21  	"github.com/cockroachdb/cockroach/pkg/util/tracing"
    22  	"github.com/opentracing/opentracing-go"
    23  )
    24  
    25  // ordinalityProcessor is the processor of the WITH ORDINALITY operator, which
    26  // adds an additional ordinal column to the result.
    27  type ordinalityProcessor struct {
    28  	execinfra.ProcessorBase
    29  
    30  	input  execinfra.RowSource
    31  	curCnt int64
    32  }
    33  
    34  var _ execinfra.Processor = &ordinalityProcessor{}
    35  var _ execinfra.RowSource = &ordinalityProcessor{}
    36  
    37  const ordinalityProcName = "ordinality"
    38  
    39  func newOrdinalityProcessor(
    40  	flowCtx *execinfra.FlowCtx,
    41  	processorID int32,
    42  	spec *execinfrapb.OrdinalitySpec,
    43  	input execinfra.RowSource,
    44  	post *execinfrapb.PostProcessSpec,
    45  	output execinfra.RowReceiver,
    46  ) (execinfra.RowSourcedProcessor, error) {
    47  	ctx := flowCtx.EvalCtx.Ctx()
    48  	o := &ordinalityProcessor{input: input, curCnt: 1}
    49  
    50  	colTypes := make([]*types.T, len(input.OutputTypes())+1)
    51  	copy(colTypes, input.OutputTypes())
    52  	colTypes[len(colTypes)-1] = types.Int
    53  	if err := o.Init(
    54  		o,
    55  		post,
    56  		colTypes,
    57  		flowCtx,
    58  		processorID,
    59  		output,
    60  		nil, /* memMonitor */
    61  		execinfra.ProcStateOpts{
    62  			InputsToDrain: []execinfra.RowSource{o.input},
    63  			TrailingMetaCallback: func(context.Context) []execinfrapb.ProducerMetadata {
    64  				o.ConsumerClosed()
    65  				return nil
    66  			}},
    67  	); err != nil {
    68  		return nil, err
    69  	}
    70  
    71  	if sp := opentracing.SpanFromContext(ctx); sp != nil && tracing.IsRecording(sp) {
    72  		o.input = newInputStatCollector(o.input)
    73  		o.FinishTrace = o.outputStatsToTrace
    74  	}
    75  
    76  	return o, nil
    77  }
    78  
    79  // Start is part of the RowSource interface.
    80  func (o *ordinalityProcessor) Start(ctx context.Context) context.Context {
    81  	o.input.Start(ctx)
    82  	return o.StartInternal(ctx, ordinalityProcName)
    83  }
    84  
    85  // Next is part of the RowSource interface.
    86  func (o *ordinalityProcessor) Next() (sqlbase.EncDatumRow, *execinfrapb.ProducerMetadata) {
    87  	for o.State == execinfra.StateRunning {
    88  		row, meta := o.input.Next()
    89  
    90  		if meta != nil {
    91  			if meta.Err != nil {
    92  				o.MoveToDraining(nil /* err */)
    93  			}
    94  			return nil, meta
    95  		}
    96  		if row == nil {
    97  			o.MoveToDraining(nil /* err */)
    98  			break
    99  		}
   100  
   101  		// The ordinality should increment even if the row gets filtered out.
   102  		row = append(row, sqlbase.DatumToEncDatum(types.Int, tree.NewDInt(tree.DInt(o.curCnt))))
   103  		o.curCnt++
   104  		if outRow := o.ProcessRowHelper(row); outRow != nil {
   105  			return outRow, nil
   106  		}
   107  	}
   108  	return nil, o.DrainHelper()
   109  
   110  }
   111  
   112  // ConsumerClosed is part of the RowSource interface.
   113  func (o *ordinalityProcessor) ConsumerClosed() {
   114  	// The consumer is done, Next() will not be called again.
   115  	o.InternalClose()
   116  }
   117  
   118  const ordinalityTagPrefix = "ordinality."
   119  
   120  // Stats implements the SpanStats interface.
   121  func (os *OrdinalityStats) Stats() map[string]string {
   122  	return os.InputStats.Stats(ordinalityTagPrefix)
   123  }
   124  
   125  // StatsForQueryPlan implements the DistSQLSpanStats interface.
   126  func (os *OrdinalityStats) StatsForQueryPlan() []string {
   127  	return os.InputStats.StatsForQueryPlan("")
   128  }
   129  
   130  // outputStatsToTrace outputs the collected distinct stats to the trace. Will
   131  // fail silently if the Distinct processor is not collecting stats.
   132  func (o *ordinalityProcessor) outputStatsToTrace() {
   133  	is, ok := getInputStats(o.FlowCtx, o.input)
   134  	if !ok {
   135  		return
   136  	}
   137  	if sp := opentracing.SpanFromContext(o.Ctx); sp != nil {
   138  		tracing.SetSpanStats(
   139  			sp, &OrdinalityStats{InputStats: is},
   140  		)
   141  	}
   142  }