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 }