github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/rowexec/utils_test.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  	"testing"
    16  
    17  	"github.com/cockroachdb/cockroach/pkg/kv"
    18  	"github.com/cockroachdb/cockroach/pkg/settings/cluster"
    19  	"github.com/cockroachdb/cockroach/pkg/sql/execinfra"
    20  	"github.com/cockroachdb/cockroach/pkg/sql/execinfrapb"
    21  	"github.com/cockroachdb/cockroach/pkg/sql/rowcontainer"
    22  	"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
    23  	"github.com/cockroachdb/cockroach/pkg/sql/sqlbase"
    24  	"github.com/cockroachdb/cockroach/pkg/sql/types"
    25  	"github.com/cockroachdb/cockroach/pkg/testutils/distsqlutils"
    26  	"github.com/cockroachdb/cockroach/pkg/testutils/sqlutils"
    27  )
    28  
    29  // runProcessorTest instantiates a processor with the provided spec, runs it
    30  // with the given inputs, and asserts that the outputted rows are as expected.
    31  func runProcessorTest(
    32  	t *testing.T,
    33  	core execinfrapb.ProcessorCoreUnion,
    34  	post execinfrapb.PostProcessSpec,
    35  	inputTypes []*types.T,
    36  	inputRows sqlbase.EncDatumRows,
    37  	outputTypes []*types.T,
    38  	expected sqlbase.EncDatumRows,
    39  	txn *kv.Txn,
    40  ) {
    41  	in := distsqlutils.NewRowBuffer(inputTypes, inputRows, distsqlutils.RowBufferArgs{})
    42  	out := &distsqlutils.RowBuffer{}
    43  
    44  	st := cluster.MakeTestingClusterSettings()
    45  	evalCtx := tree.MakeTestingEvalContext(st)
    46  	defer evalCtx.Stop(context.Background())
    47  	flowCtx := execinfra.FlowCtx{
    48  		Cfg:     &execinfra.ServerConfig{Settings: st},
    49  		EvalCtx: &evalCtx,
    50  		Txn:     txn,
    51  	}
    52  
    53  	p, err := NewProcessor(
    54  		context.Background(), &flowCtx, 0 /* processorID */, &core, &post,
    55  		[]execinfra.RowSource{in}, []execinfra.RowReceiver{out}, []execinfra.LocalProcessor{})
    56  	if err != nil {
    57  		t.Fatal(err)
    58  	}
    59  
    60  	switch pt := p.(type) {
    61  	case *joinReader:
    62  		// Reduce batch size to exercise batching logic.
    63  		pt.SetBatchSizeBytes(2 * int64(inputRows[0].Size()))
    64  	case *indexJoiner:
    65  		//	Reduce batch size to exercise batching logic.
    66  		pt.SetBatchSize(2 /* batchSize */)
    67  	}
    68  
    69  	p.Run(context.Background())
    70  	if !out.ProducerClosed() {
    71  		t.Fatalf("output RowReceiver not closed")
    72  	}
    73  	var res sqlbase.EncDatumRows
    74  	for {
    75  		row := out.NextNoMeta(t).Copy()
    76  		if row == nil {
    77  			break
    78  		}
    79  		res = append(res, row)
    80  	}
    81  
    82  	if result := res.String(outputTypes); result != expected.String(outputTypes) {
    83  		t.Errorf(
    84  			"invalid results: %s, expected %s'", result, expected.String(outputTypes))
    85  	}
    86  }
    87  
    88  type rowsAccessor interface {
    89  	getRows() *rowcontainer.DiskBackedRowContainer
    90  }
    91  
    92  func (s *sorterBase) getRows() *rowcontainer.DiskBackedRowContainer {
    93  	return s.rows.(*rowcontainer.DiskBackedRowContainer)
    94  }
    95  
    96  type rowGeneratingSource struct {
    97  	types              []*types.T
    98  	fn                 sqlutils.GenRowFn
    99  	scratchEncDatumRow sqlbase.EncDatumRow
   100  
   101  	rowIdx  int
   102  	maxRows int
   103  }
   104  
   105  // newRowGeneratingSource creates a new rowGeneratingSource with the given fn
   106  // and a maximum number of rows to generate. Can be reset using Reset.
   107  func newRowGeneratingSource(
   108  	types []*types.T, fn sqlutils.GenRowFn, maxRows int,
   109  ) *rowGeneratingSource {
   110  	return &rowGeneratingSource{types: types, fn: fn, rowIdx: 1, maxRows: maxRows}
   111  }
   112  
   113  func (r *rowGeneratingSource) OutputTypes() []*types.T { return r.types }
   114  
   115  func (r *rowGeneratingSource) Start(ctx context.Context) context.Context { return ctx }
   116  
   117  func (r *rowGeneratingSource) Next() (sqlbase.EncDatumRow, *execinfrapb.ProducerMetadata) {
   118  	if r.rowIdx > r.maxRows {
   119  		// Done.
   120  		return nil, nil
   121  	}
   122  
   123  	datumRow := r.fn(r.rowIdx)
   124  	if cap(r.scratchEncDatumRow) < len(datumRow) {
   125  		r.scratchEncDatumRow = make(sqlbase.EncDatumRow, len(datumRow))
   126  	} else {
   127  		r.scratchEncDatumRow = r.scratchEncDatumRow[:len(datumRow)]
   128  	}
   129  
   130  	for i := range r.scratchEncDatumRow {
   131  		r.scratchEncDatumRow[i] = sqlbase.DatumToEncDatum(r.types[i], datumRow[i])
   132  	}
   133  	r.rowIdx++
   134  	return r.scratchEncDatumRow, nil
   135  }
   136  
   137  // Reset resets this rowGeneratingSource so that the next rowIdx passed to the
   138  // generating function is 1.
   139  func (r *rowGeneratingSource) Reset() {
   140  	r.rowIdx = 1
   141  }
   142  
   143  func (r *rowGeneratingSource) ConsumerDone() {}
   144  
   145  func (r *rowGeneratingSource) ConsumerClosed() {}
   146  
   147  // rowDisposer is a RowReceiver that discards any rows Push()ed.
   148  type rowDisposer struct {
   149  	bufferedMeta    []execinfrapb.ProducerMetadata
   150  	numRowsDisposed int
   151  }
   152  
   153  var _ execinfra.RowReceiver = &rowDisposer{}
   154  
   155  // Push is part of the distsql.RowReceiver interface.
   156  func (r *rowDisposer) Push(
   157  	row sqlbase.EncDatumRow, meta *execinfrapb.ProducerMetadata,
   158  ) execinfra.ConsumerStatus {
   159  	if row != nil {
   160  		r.numRowsDisposed++
   161  	} else if meta != nil {
   162  		r.bufferedMeta = append(r.bufferedMeta, *meta)
   163  	}
   164  	return execinfra.NeedMoreRows
   165  }
   166  
   167  // ProducerDone is part of the RowReceiver interface.
   168  func (r *rowDisposer) ProducerDone() {}
   169  
   170  // Types is part of the RowReceiver interface.
   171  func (r *rowDisposer) Types() []*types.T {
   172  	return nil
   173  }
   174  
   175  func (r *rowDisposer) ResetNumRowsDisposed() {
   176  	r.numRowsDisposed = 0
   177  }
   178  
   179  func (r *rowDisposer) NumRowsDisposed() int {
   180  	return r.numRowsDisposed
   181  }
   182  
   183  func (r *rowDisposer) DrainMeta(context.Context) []execinfrapb.ProducerMetadata {
   184  	return r.bufferedMeta
   185  }