github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/rowexec/project_set.go (about) 1 // Copyright 2018 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 "fmt" 16 17 "github.com/cockroachdb/cockroach/pkg/sql/execinfra" 18 "github.com/cockroachdb/cockroach/pkg/sql/execinfrapb" 19 "github.com/cockroachdb/cockroach/pkg/sql/sem/builtins" 20 "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" 21 "github.com/cockroachdb/cockroach/pkg/sql/sqlbase" 22 ) 23 24 // projectSetProcessor is the physical processor implementation of 25 // projectSetNode. 26 type projectSetProcessor struct { 27 execinfra.ProcessorBase 28 29 input execinfra.RowSource 30 spec *execinfrapb.ProjectSetSpec 31 32 // exprHelpers are the constant-folded, type checked expressions specified 33 // in the ROWS FROM syntax. This can contain many kinds of expressions 34 // (anything that is "function-like" including COALESCE, NULLIF) not just 35 // SRFs. 36 exprHelpers []*execinfra.ExprHelper 37 38 // funcs contains a valid pointer to a SRF FuncExpr for every entry 39 // in `exprHelpers` that is actually a SRF function application. 40 // The size of the slice is the same as `exprHelpers` though. 41 funcs []*tree.FuncExpr 42 43 // inputRowReady is set when there was a row of input data available 44 // from the source. 45 inputRowReady bool 46 47 // RowBuffer will contain the current row of results. 48 rowBuffer sqlbase.EncDatumRow 49 50 // gens contains the current "active" ValueGenerators for each entry 51 // in `funcs`. They are initialized anew for every new row in the source. 52 gens []tree.ValueGenerator 53 54 // done indicates for each `Expr` whether the values produced by 55 // either the SRF or the scalar expressions are fully consumed and 56 // thus also whether NULLs should be emitted instead. 57 done []bool 58 59 // emitCount is used to track the number of rows that have been 60 // emitted from Next(). 61 emitCount int64 62 } 63 64 var _ execinfra.Processor = &projectSetProcessor{} 65 var _ execinfra.RowSource = &projectSetProcessor{} 66 var _ execinfra.OpNode = &projectSetProcessor{} 67 68 const projectSetProcName = "projectSet" 69 70 func newProjectSetProcessor( 71 flowCtx *execinfra.FlowCtx, 72 processorID int32, 73 spec *execinfrapb.ProjectSetSpec, 74 input execinfra.RowSource, 75 post *execinfrapb.PostProcessSpec, 76 output execinfra.RowReceiver, 77 ) (*projectSetProcessor, error) { 78 outputTypes := append(input.OutputTypes(), spec.GeneratedColumns...) 79 ps := &projectSetProcessor{ 80 input: input, 81 spec: spec, 82 exprHelpers: make([]*execinfra.ExprHelper, len(spec.Exprs)), 83 funcs: make([]*tree.FuncExpr, len(spec.Exprs)), 84 rowBuffer: make(sqlbase.EncDatumRow, len(outputTypes)), 85 gens: make([]tree.ValueGenerator, len(spec.Exprs)), 86 done: make([]bool, len(spec.Exprs)), 87 } 88 if err := ps.Init( 89 ps, 90 post, 91 outputTypes, 92 flowCtx, 93 processorID, 94 output, 95 nil, /* memMonitor */ 96 execinfra.ProcStateOpts{InputsToDrain: []execinfra.RowSource{ps.input}}, 97 ); err != nil { 98 return nil, err 99 } 100 return ps, nil 101 } 102 103 // Start is part of the RowSource interface. 104 func (ps *projectSetProcessor) Start(ctx context.Context) context.Context { 105 ps.input.Start(ctx) 106 ctx = ps.StartInternal(ctx, projectSetProcName) 107 108 // Initialize exprHelpers. 109 for i, expr := range ps.spec.Exprs { 110 var helper execinfra.ExprHelper 111 err := helper.Init(expr, ps.input.OutputTypes(), ps.EvalCtx) 112 if err != nil { 113 ps.MoveToDraining(err) 114 return ctx 115 } 116 if tFunc, ok := helper.Expr.(*tree.FuncExpr); ok && tFunc.IsGeneratorApplication() { 117 // Expr is a set-generating function. 118 ps.funcs[i] = tFunc 119 } 120 ps.exprHelpers[i] = &helper 121 } 122 return ctx 123 } 124 125 // nextInputRow returns the next row or metadata from ps.input. It also 126 // initializes the value generators for that row. 127 func (ps *projectSetProcessor) nextInputRow() ( 128 sqlbase.EncDatumRow, 129 *execinfrapb.ProducerMetadata, 130 error, 131 ) { 132 row, meta := ps.input.Next() 133 if row == nil { 134 return nil, meta, nil 135 } 136 137 // Initialize a round of SRF generators or scalar values. 138 for i := range ps.exprHelpers { 139 if fn := ps.funcs[i]; fn != nil { 140 // A set-generating function. Prepare its ValueGenerator. 141 142 // Set ExprHelper.row so that we can use it as an IndexedVarContainer. 143 ps.exprHelpers[i].Row = row 144 145 ps.EvalCtx.IVarContainer = ps.exprHelpers[i] 146 gen, err := fn.EvalArgsAndGetGenerator(ps.EvalCtx) 147 if err != nil { 148 return nil, nil, err 149 } 150 if gen == nil { 151 gen = builtins.EmptyGenerator() 152 } 153 if err := gen.Start(ps.Ctx, ps.FlowCtx.Txn); err != nil { 154 return nil, nil, err 155 } 156 ps.gens[i] = gen 157 } 158 ps.done[i] = false 159 } 160 161 return row, nil, nil 162 } 163 164 // nextGeneratorValues populates the row buffer with the next set of generated 165 // values. It returns true if any of the generators produce new values. 166 func (ps *projectSetProcessor) nextGeneratorValues() (newValAvail bool, err error) { 167 colIdx := len(ps.input.OutputTypes()) 168 for i := range ps.exprHelpers { 169 // Do we have a SRF? 170 if gen := ps.gens[i]; gen != nil { 171 // Yes. Is there still work to do for the current row? 172 numCols := int(ps.spec.NumColsPerGen[i]) 173 if !ps.done[i] { 174 // Yes; check whether this source still has some values available. 175 hasVals, err := gen.Next(ps.Ctx) 176 if err != nil { 177 return false, err 178 } 179 if hasVals { 180 // This source has values, use them. 181 values, err := gen.Values() 182 if err != nil { 183 return false, err 184 } 185 for _, value := range values { 186 ps.rowBuffer[colIdx] = ps.toEncDatum(value, colIdx) 187 colIdx++ 188 } 189 newValAvail = true 190 } else { 191 ps.done[i] = true 192 // No values left. Fill the buffer with NULLs for future results. 193 for j := 0; j < numCols; j++ { 194 ps.rowBuffer[colIdx] = ps.toEncDatum(tree.DNull, colIdx) 195 colIdx++ 196 } 197 } 198 } else { 199 // Already done. Increment colIdx. 200 colIdx += numCols 201 } 202 } else { 203 // A simple scalar result. 204 // Do we still need to produce the scalar value? (first row) 205 if !ps.done[i] { 206 // Yes. Produce it once, then indicate it's "done". 207 value, err := ps.exprHelpers[i].Eval(ps.rowBuffer) 208 if err != nil { 209 return false, err 210 } 211 ps.rowBuffer[colIdx] = ps.toEncDatum(value, colIdx) 212 colIdx++ 213 newValAvail = true 214 ps.done[i] = true 215 } else { 216 // Ensure that every row after the first returns a NULL value. 217 ps.rowBuffer[colIdx] = ps.toEncDatum(tree.DNull, colIdx) 218 colIdx++ 219 } 220 } 221 } 222 return newValAvail, nil 223 } 224 225 // Next is part of the RowSource interface. 226 func (ps *projectSetProcessor) Next() (sqlbase.EncDatumRow, *execinfrapb.ProducerMetadata) { 227 const cancelCheckCount = 10000 228 229 for ps.State == execinfra.StateRunning { 230 231 // Occasionally check for cancellation. 232 ps.emitCount++ 233 if ps.emitCount%cancelCheckCount == 0 { 234 if err := ps.Ctx.Err(); err != nil { 235 ps.MoveToDraining(err) 236 return nil, ps.DrainHelper() 237 } 238 } 239 240 // Start of a new row of input? 241 if !ps.inputRowReady { 242 // Read the row from the source. 243 row, meta, err := ps.nextInputRow() 244 if meta != nil { 245 if meta.Err != nil { 246 ps.MoveToDraining(nil /* err */) 247 } 248 return nil, meta 249 } 250 if err != nil { 251 ps.MoveToDraining(err) 252 return nil, ps.DrainHelper() 253 } 254 if row == nil { 255 ps.MoveToDraining(nil /* err */) 256 return nil, ps.DrainHelper() 257 } 258 259 // Keep the values for later. 260 copy(ps.rowBuffer, row) 261 ps.inputRowReady = true 262 } 263 264 // Try to find some data on the generator side. 265 newValAvail, err := ps.nextGeneratorValues() 266 if err != nil { 267 ps.MoveToDraining(err) 268 return nil, ps.DrainHelper() 269 } 270 if newValAvail { 271 if outRow := ps.ProcessRowHelper(ps.rowBuffer); outRow != nil { 272 return outRow, nil 273 } 274 } else { 275 // The current batch of SRF values was exhausted. Advance 276 // to the next input row. 277 ps.inputRowReady = false 278 } 279 } 280 return nil, ps.DrainHelper() 281 } 282 283 func (ps *projectSetProcessor) toEncDatum(d tree.Datum, colIdx int) sqlbase.EncDatum { 284 generatedColIdx := colIdx - len(ps.input.OutputTypes()) 285 ctyp := ps.spec.GeneratedColumns[generatedColIdx] 286 return sqlbase.DatumToEncDatum(ctyp, d) 287 } 288 289 // ConsumerClosed is part of the RowSource interface. 290 func (ps *projectSetProcessor) ConsumerClosed() { 291 // The consumer is done, Next() will not be called again. 292 ps.InternalClose() 293 } 294 295 // ChildCount is part of the execinfra.OpNode interface. 296 func (ps *projectSetProcessor) ChildCount(verbose bool) int { 297 if _, ok := ps.input.(execinfra.OpNode); ok { 298 return 1 299 } 300 return 0 301 } 302 303 // Child is part of the execinfra.OpNode interface. 304 func (ps *projectSetProcessor) Child(nth int, verbose bool) execinfra.OpNode { 305 if nth == 0 { 306 if n, ok := ps.input.(execinfra.OpNode); ok { 307 return n 308 } 309 panic("input to projectSetProcessor is not an execinfra.OpNode") 310 311 } 312 panic(fmt.Sprintf("invalid index %d", nth)) 313 }