github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/colexec/colbatch_scan.go (about) 1 // Copyright 2016 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 colexec 12 13 import ( 14 "context" 15 16 "github.com/cockroachdb/cockroach/pkg/col/coldata" 17 "github.com/cockroachdb/cockroach/pkg/keys" 18 "github.com/cockroachdb/cockroach/pkg/roachpb" 19 "github.com/cockroachdb/cockroach/pkg/sql/colexecbase" 20 "github.com/cockroachdb/cockroach/pkg/sql/colexecbase/colexecerror" 21 "github.com/cockroachdb/cockroach/pkg/sql/colmem" 22 "github.com/cockroachdb/cockroach/pkg/sql/execinfra" 23 "github.com/cockroachdb/cockroach/pkg/sql/execinfrapb" 24 "github.com/cockroachdb/cockroach/pkg/sql/row" 25 "github.com/cockroachdb/cockroach/pkg/sql/sqlbase" 26 "github.com/cockroachdb/cockroach/pkg/util" 27 "github.com/cockroachdb/errors" 28 ) 29 30 // TODO(yuzefovich): reading the data through a pair of colBatchScan and 31 // materializer turns out to be more efficient than through a table reader (at 32 // the moment, the exception is the case of reading very small number of rows 33 // because we still pre-allocate batches of 1024 size). Once we can control the 34 // initial size of pre-allocated batches (probably via a batch allocator), we 35 // should get rid off table readers entirely. We will have to be careful about 36 // propagating the metadata though. 37 38 // colBatchScan is the exec.Operator implementation of TableReader. It reads a table 39 // from kv, presenting it as coldata.Batches via the exec.Operator interface. 40 type colBatchScan struct { 41 colexecbase.ZeroInputNode 42 spans roachpb.Spans 43 flowCtx *execinfra.FlowCtx 44 rf *cFetcher 45 limitHint int64 46 ctx context.Context 47 // maxResults is non-zero if there is a limit on the total number of rows 48 // that the colBatchScan will read. 49 maxResults uint64 50 // init is true after Init() has been called. 51 init bool 52 } 53 54 var _ colexecbase.Operator = &colBatchScan{} 55 56 func (s *colBatchScan) Init() { 57 s.ctx = context.Background() 58 s.init = true 59 60 limitBatches := execinfra.ScanShouldLimitBatches(s.maxResults, s.limitHint, s.flowCtx) 61 62 if err := s.rf.StartScan( 63 s.ctx, s.flowCtx.Txn, s.spans, 64 limitBatches, s.limitHint, s.flowCtx.TraceKV, 65 ); err != nil { 66 colexecerror.InternalError(err) 67 } 68 } 69 70 func (s *colBatchScan) Next(ctx context.Context) coldata.Batch { 71 bat, err := s.rf.NextBatch(ctx) 72 if err != nil { 73 colexecerror.InternalError(err) 74 } 75 if bat.Selection() != nil { 76 colexecerror.InternalError("unexpectedly a selection vector is set on the batch coming from CFetcher") 77 } 78 return bat 79 } 80 81 // DrainMeta is part of the MetadataSource interface. 82 func (s *colBatchScan) DrainMeta(ctx context.Context) []execinfrapb.ProducerMetadata { 83 if !s.init { 84 // In some pathological queries like `SELECT 1 FROM t HAVING true`, Init() 85 // and Next() may never get called. Return early to avoid using an 86 // uninitialized fetcher. 87 return nil 88 } 89 var trailingMeta []execinfrapb.ProducerMetadata 90 if !s.flowCtx.Local { 91 nodeID, ok := s.flowCtx.NodeID.OptionalNodeID() 92 if ok { 93 ranges := execinfra.MisplannedRanges(ctx, s.rf.GetRangesInfo(), nodeID) 94 if ranges != nil { 95 trailingMeta = append(trailingMeta, execinfrapb.ProducerMetadata{Ranges: ranges}) 96 } 97 } 98 } 99 if tfs := execinfra.GetLeafTxnFinalState(ctx, s.flowCtx.Txn); tfs != nil { 100 trailingMeta = append(trailingMeta, execinfrapb.ProducerMetadata{LeafTxnFinalState: tfs}) 101 } 102 return trailingMeta 103 } 104 105 // newColBatchScan creates a new colBatchScan operator. 106 func newColBatchScan( 107 allocator *colmem.Allocator, 108 flowCtx *execinfra.FlowCtx, 109 spec *execinfrapb.TableReaderSpec, 110 post *execinfrapb.PostProcessSpec, 111 ) (*colBatchScan, error) { 112 // NB: we hit this with a zero NodeID (but !ok) with multi-tenancy. 113 if nodeID, ok := flowCtx.NodeID.OptionalNodeID(); nodeID == 0 && ok { 114 return nil, errors.Errorf("attempting to create a colBatchScan with uninitialized NodeID") 115 } 116 117 limitHint := execinfra.LimitHint(spec.LimitHint, post) 118 119 returnMutations := spec.Visibility == execinfra.ScanVisibilityPublicAndNotPublic 120 typs := spec.Table.ColumnTypesWithMutations(returnMutations) 121 evalCtx := flowCtx.NewEvalCtx() 122 // Before we can safely use types from the table descriptor, we need to 123 // make sure they are hydrated. In row execution engine it is done during 124 // the processor initialization, but neither colBatchScan nor cFetcher are 125 // processors, so we need to do the hydration ourselves. 126 if err := execinfrapb.HydrateTypeSlice(evalCtx, typs); err != nil { 127 return nil, err 128 } 129 helper := execinfra.ProcOutputHelper{} 130 if err := helper.Init( 131 post, 132 typs, 133 evalCtx, 134 nil, /* output */ 135 ); err != nil { 136 return nil, err 137 } 138 139 neededColumns := helper.NeededColumns() 140 141 columnIdxMap := spec.Table.ColumnIdxMapWithMutations(returnMutations) 142 fetcher := cFetcher{} 143 if _, _, err := initCRowFetcher( 144 flowCtx.Codec(), allocator, &fetcher, &spec.Table, int(spec.IndexIdx), columnIdxMap, 145 spec.Reverse, neededColumns, spec.IsCheck, spec.Visibility, spec.LockingStrength, 146 ); err != nil { 147 return nil, err 148 } 149 150 nSpans := len(spec.Spans) 151 spans := make(roachpb.Spans, nSpans) 152 for i := range spans { 153 spans[i] = spec.Spans[i].Span 154 } 155 return &colBatchScan{ 156 spans: spans, 157 flowCtx: flowCtx, 158 rf: &fetcher, 159 limitHint: limitHint, 160 maxResults: spec.MaxResults, 161 }, nil 162 } 163 164 // initCRowFetcher initializes a row.cFetcher. See initRowFetcher. 165 func initCRowFetcher( 166 codec keys.SQLCodec, 167 allocator *colmem.Allocator, 168 fetcher *cFetcher, 169 desc *sqlbase.TableDescriptor, 170 indexIdx int, 171 colIdxMap map[sqlbase.ColumnID]int, 172 reverseScan bool, 173 valNeededForCol util.FastIntSet, 174 isCheck bool, 175 scanVisibility execinfrapb.ScanVisibility, 176 lockStr sqlbase.ScanLockingStrength, 177 ) (index *sqlbase.IndexDescriptor, isSecondaryIndex bool, err error) { 178 immutDesc := sqlbase.NewImmutableTableDescriptor(*desc) 179 index, isSecondaryIndex, err = immutDesc.FindIndexByIndexIdx(indexIdx) 180 if err != nil { 181 return nil, false, err 182 } 183 184 cols := immutDesc.Columns 185 if scanVisibility == execinfra.ScanVisibilityPublicAndNotPublic { 186 cols = immutDesc.ReadableColumns 187 } 188 tableArgs := row.FetcherTableArgs{ 189 Desc: immutDesc, 190 Index: index, 191 ColIdxMap: colIdxMap, 192 IsSecondaryIndex: isSecondaryIndex, 193 Cols: cols, 194 ValNeededForCol: valNeededForCol, 195 } 196 if err := fetcher.Init( 197 codec, allocator, reverseScan, lockStr, true /* returnRangeInfo */, isCheck, tableArgs, 198 ); err != nil { 199 return nil, false, err 200 } 201 202 return index, isSecondaryIndex, nil 203 }