github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/rowexec/processors.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/sqlbase"
    19  	"github.com/cockroachdb/cockroach/pkg/util/log"
    20  	"github.com/cockroachdb/errors"
    21  )
    22  
    23  // emitHelper is a utility wrapper on top of ProcOutputHelper.EmitRow().
    24  // It takes a row to emit and, if anything happens other than the normal
    25  // situation where the emitting succeeds and the consumer still needs rows, both
    26  // the (potentially many) inputs and the output are properly closed after
    27  // potentially draining the inputs. It's allowed to not pass any inputs, in
    28  // which case nothing will be drained (this can happen when the caller has
    29  // already fully consumed the inputs).
    30  //
    31  // As opposed to EmitRow(), this also supports metadata rows which bypass the
    32  // ProcOutputHelper and are routed directly to its output.
    33  //
    34  // If the consumer signals the producer to drain, the message is relayed and all
    35  // the draining metadata is consumed and forwarded.
    36  //
    37  // inputs are optional.
    38  //
    39  // pushTrailingMeta is called after draining the sources and before calling
    40  // dst.ProducerDone(). It gives the caller the opportunity to push some trailing
    41  // metadata (e.g. tracing information and txn updates, if applicable).
    42  //
    43  // Returns true if more rows are needed, false otherwise. If false is returned
    44  // both the inputs and the output have been properly closed.
    45  func emitHelper(
    46  	ctx context.Context,
    47  	output *execinfra.ProcOutputHelper,
    48  	row sqlbase.EncDatumRow,
    49  	meta *execinfrapb.ProducerMetadata,
    50  	pushTrailingMeta func(context.Context),
    51  	inputs ...execinfra.RowSource,
    52  ) bool {
    53  	if output.Output() == nil {
    54  		panic("output RowReceiver not initialized for emitting")
    55  	}
    56  	var consumerStatus execinfra.ConsumerStatus
    57  	if meta != nil {
    58  		if row != nil {
    59  			panic("both row data and metadata in the same emitHelper call")
    60  		}
    61  		// Bypass EmitRow() and send directly to output.output.
    62  		foundErr := meta.Err != nil
    63  		consumerStatus = output.Output().Push(nil /* row */, meta)
    64  		if foundErr {
    65  			consumerStatus = execinfra.ConsumerClosed
    66  		}
    67  	} else {
    68  		var err error
    69  		consumerStatus, err = output.EmitRow(ctx, row)
    70  		if err != nil {
    71  			output.Output().Push(nil /* row */, &execinfrapb.ProducerMetadata{Err: err})
    72  			consumerStatus = execinfra.ConsumerClosed
    73  		}
    74  	}
    75  	switch consumerStatus {
    76  	case execinfra.NeedMoreRows:
    77  		return true
    78  	case execinfra.DrainRequested:
    79  		log.VEventf(ctx, 1, "no more rows required. drain requested.")
    80  		execinfra.DrainAndClose(ctx, output.Output(), nil /* cause */, pushTrailingMeta, inputs...)
    81  		return false
    82  	case execinfra.ConsumerClosed:
    83  		log.VEventf(ctx, 1, "no more rows required. Consumer shut down.")
    84  		for _, input := range inputs {
    85  			input.ConsumerClosed()
    86  		}
    87  		output.Close()
    88  		return false
    89  	default:
    90  		log.Fatalf(ctx, "unexpected consumerStatus: %d", consumerStatus)
    91  		return false
    92  	}
    93  }
    94  
    95  func checkNumInOut(
    96  	inputs []execinfra.RowSource, outputs []execinfra.RowReceiver, numIn, numOut int,
    97  ) error {
    98  	if len(inputs) != numIn {
    99  		return errors.Errorf("expected %d input(s), got %d", numIn, len(inputs))
   100  	}
   101  	if len(outputs) != numOut {
   102  		return errors.Errorf("expected %d output(s), got %d", numOut, len(outputs))
   103  	}
   104  	return nil
   105  }
   106  
   107  // NewProcessor creates a new execinfra.Processor according to the provided
   108  // core.
   109  func NewProcessor(
   110  	ctx context.Context,
   111  	flowCtx *execinfra.FlowCtx,
   112  	processorID int32,
   113  	core *execinfrapb.ProcessorCoreUnion,
   114  	post *execinfrapb.PostProcessSpec,
   115  	inputs []execinfra.RowSource,
   116  	outputs []execinfra.RowReceiver,
   117  	localProcessors []execinfra.LocalProcessor,
   118  ) (execinfra.Processor, error) {
   119  	if core.Noop != nil {
   120  		if err := checkNumInOut(inputs, outputs, 1, 1); err != nil {
   121  			return nil, err
   122  		}
   123  		return newNoopProcessor(flowCtx, processorID, inputs[0], post, outputs[0])
   124  	}
   125  	if core.Values != nil {
   126  		if err := checkNumInOut(inputs, outputs, 0, 1); err != nil {
   127  			return nil, err
   128  		}
   129  		return newValuesProcessor(flowCtx, processorID, core.Values, post, outputs[0])
   130  	}
   131  	if core.TableReader != nil {
   132  		if err := checkNumInOut(inputs, outputs, 0, 1); err != nil {
   133  			return nil, err
   134  		}
   135  		if core.TableReader.IsCheck {
   136  			return newScrubTableReader(flowCtx, processorID, core.TableReader, post, outputs[0])
   137  		}
   138  		return newTableReader(flowCtx, processorID, core.TableReader, post, outputs[0])
   139  	}
   140  	if core.JoinReader != nil {
   141  		if err := checkNumInOut(inputs, outputs, 1, 1); err != nil {
   142  			return nil, err
   143  		}
   144  		if len(core.JoinReader.LookupColumns) == 0 {
   145  			return newIndexJoiner(
   146  				flowCtx, processorID, core.JoinReader, inputs[0], post, outputs[0])
   147  		}
   148  		return newJoinReader(flowCtx, processorID, core.JoinReader, inputs[0], post, outputs[0])
   149  	}
   150  	if core.Sorter != nil {
   151  		if err := checkNumInOut(inputs, outputs, 1, 1); err != nil {
   152  			return nil, err
   153  		}
   154  		return newSorter(ctx, flowCtx, processorID, core.Sorter, inputs[0], post, outputs[0])
   155  	}
   156  	if core.Distinct != nil {
   157  		if err := checkNumInOut(inputs, outputs, 1, 1); err != nil {
   158  			return nil, err
   159  		}
   160  		return newDistinct(flowCtx, processorID, core.Distinct, inputs[0], post, outputs[0])
   161  	}
   162  	if core.Ordinality != nil {
   163  		if err := checkNumInOut(inputs, outputs, 1, 1); err != nil {
   164  			return nil, err
   165  		}
   166  		return newOrdinalityProcessor(flowCtx, processorID, core.Ordinality, inputs[0], post, outputs[0])
   167  	}
   168  	if core.Aggregator != nil {
   169  		if err := checkNumInOut(inputs, outputs, 1, 1); err != nil {
   170  			return nil, err
   171  		}
   172  		return newAggregator(flowCtx, processorID, core.Aggregator, inputs[0], post, outputs[0])
   173  	}
   174  	if core.MergeJoiner != nil {
   175  		if err := checkNumInOut(inputs, outputs, 2, 1); err != nil {
   176  			return nil, err
   177  		}
   178  		return newMergeJoiner(
   179  			flowCtx, processorID, core.MergeJoiner, inputs[0], inputs[1], post, outputs[0],
   180  		)
   181  	}
   182  	if core.InterleavedReaderJoiner != nil {
   183  		if err := checkNumInOut(inputs, outputs, 0, 1); err != nil {
   184  			return nil, err
   185  		}
   186  		return newInterleavedReaderJoiner(
   187  			flowCtx, processorID, core.InterleavedReaderJoiner, post, outputs[0],
   188  		)
   189  	}
   190  	if core.ZigzagJoiner != nil {
   191  		if err := checkNumInOut(inputs, outputs, 0, 1); err != nil {
   192  			return nil, err
   193  		}
   194  		return newZigzagJoiner(
   195  			flowCtx, processorID, core.ZigzagJoiner, nil, post, outputs[0],
   196  		)
   197  	}
   198  	if core.HashJoiner != nil {
   199  		if err := checkNumInOut(inputs, outputs, 2, 1); err != nil {
   200  			return nil, err
   201  		}
   202  		return newHashJoiner(
   203  			flowCtx, processorID, core.HashJoiner, inputs[0], inputs[1], post,
   204  			outputs[0], false, /* disableTempStorage */
   205  		)
   206  	}
   207  	if core.Backfiller != nil {
   208  		if err := checkNumInOut(inputs, outputs, 0, 1); err != nil {
   209  			return nil, err
   210  		}
   211  		switch core.Backfiller.Type {
   212  		case execinfrapb.BackfillerSpec_Index:
   213  			return newIndexBackfiller(flowCtx, processorID, *core.Backfiller, post, outputs[0])
   214  		case execinfrapb.BackfillerSpec_Column:
   215  			return newColumnBackfiller(ctx, flowCtx, processorID, *core.Backfiller, post, outputs[0])
   216  		}
   217  	}
   218  	if core.Sampler != nil {
   219  		if err := checkNumInOut(inputs, outputs, 1, 1); err != nil {
   220  			return nil, err
   221  		}
   222  		return newSamplerProcessor(flowCtx, processorID, core.Sampler, inputs[0], post, outputs[0])
   223  	}
   224  	if core.SampleAggregator != nil {
   225  		if err := checkNumInOut(inputs, outputs, 1, 1); err != nil {
   226  			return nil, err
   227  		}
   228  		return newSampleAggregator(flowCtx, processorID, core.SampleAggregator, inputs[0], post, outputs[0])
   229  	}
   230  	if core.ReadImport != nil {
   231  		if err := checkNumInOut(inputs, outputs, 0, 1); err != nil {
   232  			return nil, err
   233  		}
   234  		if NewReadImportDataProcessor == nil {
   235  			return nil, errors.New("ReadImportData processor unimplemented")
   236  		}
   237  		return NewReadImportDataProcessor(flowCtx, processorID, *core.ReadImport, outputs[0])
   238  	}
   239  	if core.CSVWriter != nil {
   240  		if err := checkNumInOut(inputs, outputs, 1, 1); err != nil {
   241  			return nil, err
   242  		}
   243  		if NewCSVWriterProcessor == nil {
   244  			return nil, errors.New("CSVWriter processor unimplemented")
   245  		}
   246  		return NewCSVWriterProcessor(flowCtx, processorID, *core.CSVWriter, inputs[0], outputs[0])
   247  	}
   248  	if core.BulkRowWriter != nil {
   249  		if err := checkNumInOut(inputs, outputs, 1, 1); err != nil {
   250  			return nil, err
   251  		}
   252  		return newBulkRowWriterProcessor(flowCtx, processorID, *core.BulkRowWriter, inputs[0], outputs[0])
   253  	}
   254  	if core.MetadataTestSender != nil {
   255  		if err := checkNumInOut(inputs, outputs, 1, 1); err != nil {
   256  			return nil, err
   257  		}
   258  		return execinfra.NewMetadataTestSender(flowCtx, processorID, inputs[0], post, outputs[0], core.MetadataTestSender.ID)
   259  	}
   260  	if core.MetadataTestReceiver != nil {
   261  		if err := checkNumInOut(inputs, outputs, 1, 1); err != nil {
   262  			return nil, err
   263  		}
   264  		return execinfra.NewMetadataTestReceiver(
   265  			flowCtx, processorID, inputs[0], post, outputs[0], core.MetadataTestReceiver.SenderIDs,
   266  		)
   267  	}
   268  	if core.ProjectSet != nil {
   269  		if err := checkNumInOut(inputs, outputs, 1, 1); err != nil {
   270  			return nil, err
   271  		}
   272  		return newProjectSetProcessor(flowCtx, processorID, core.ProjectSet, inputs[0], post, outputs[0])
   273  	}
   274  	if core.Windower != nil {
   275  		if err := checkNumInOut(inputs, outputs, 1, 1); err != nil {
   276  			return nil, err
   277  		}
   278  		return newWindower(flowCtx, processorID, core.Windower, inputs[0], post, outputs[0])
   279  	}
   280  	if core.LocalPlanNode != nil {
   281  		numInputs := 0
   282  		if core.LocalPlanNode.NumInputs != nil {
   283  			numInputs = int(*core.LocalPlanNode.NumInputs)
   284  		}
   285  		if err := checkNumInOut(inputs, outputs, numInputs, 1); err != nil {
   286  			return nil, err
   287  		}
   288  		processor := localProcessors[*core.LocalPlanNode.RowSourceIdx]
   289  		if err := processor.InitWithOutput(post, outputs[0]); err != nil {
   290  			return nil, err
   291  		}
   292  		if numInputs == 1 {
   293  			if err := processor.SetInput(ctx, inputs[0]); err != nil {
   294  				return nil, err
   295  			}
   296  		} else if numInputs > 1 {
   297  			return nil, errors.Errorf("invalid localPlanNode core with multiple inputs %+v", core.LocalPlanNode)
   298  		}
   299  		return processor, nil
   300  	}
   301  	if core.ChangeAggregator != nil {
   302  		if err := checkNumInOut(inputs, outputs, 0, 1); err != nil {
   303  			return nil, err
   304  		}
   305  		if NewChangeAggregatorProcessor == nil {
   306  			return nil, errors.New("ChangeAggregator processor unimplemented")
   307  		}
   308  		return NewChangeAggregatorProcessor(flowCtx, processorID, *core.ChangeAggregator, outputs[0])
   309  	}
   310  	if core.ChangeFrontier != nil {
   311  		if err := checkNumInOut(inputs, outputs, 1, 1); err != nil {
   312  			return nil, err
   313  		}
   314  		if NewChangeFrontierProcessor == nil {
   315  			return nil, errors.New("ChangeFrontier processor unimplemented")
   316  		}
   317  		return NewChangeFrontierProcessor(flowCtx, processorID, *core.ChangeFrontier, inputs[0], outputs[0])
   318  	}
   319  	if core.InvertedFilterer != nil {
   320  		if err := checkNumInOut(inputs, outputs, 1, 1); err != nil {
   321  			return nil, err
   322  		}
   323  		return newInvertedFilterer(flowCtx, processorID, core.InvertedFilterer, inputs[0], post, outputs[0])
   324  	}
   325  	return nil, errors.Errorf("unsupported processor core %q", core)
   326  }
   327  
   328  // NewReadImportDataProcessor is externally implemented and registered by
   329  // ccl/sqlccl/csv.go.
   330  var NewReadImportDataProcessor func(*execinfra.FlowCtx, int32, execinfrapb.ReadImportDataSpec, execinfra.RowReceiver) (execinfra.Processor, error)
   331  
   332  // NewCSVWriterProcessor is externally implemented.
   333  var NewCSVWriterProcessor func(*execinfra.FlowCtx, int32, execinfrapb.CSVWriterSpec, execinfra.RowSource, execinfra.RowReceiver) (execinfra.Processor, error)
   334  
   335  // NewChangeAggregatorProcessor is externally implemented.
   336  var NewChangeAggregatorProcessor func(*execinfra.FlowCtx, int32, execinfrapb.ChangeAggregatorSpec, execinfra.RowReceiver) (execinfra.Processor, error)
   337  
   338  // NewChangeFrontierProcessor is externally implemented.
   339  var NewChangeFrontierProcessor func(*execinfra.FlowCtx, int32, execinfrapb.ChangeFrontierSpec, execinfra.RowSource, execinfra.RowReceiver) (execinfra.Processor, error)