github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/opt/norm/project_builder.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 norm 12 13 import ( 14 "github.com/cockroachdb/cockroach/pkg/sql/opt" 15 "github.com/cockroachdb/cockroach/pkg/sql/opt/memo" 16 ) 17 18 // projectBuilder is a helper for constructing a ProjectOp that augments an 19 // input with new synthesized and passthrough columns. Sample usage: 20 // 21 // var pb projectBuilder 22 // pb.init(c) 23 // e1 := pb.add(some expression) 24 // e2 := pb.add(some other expression) 25 // augmentedInput := pb.buildProject(input, passthrough) 26 // // e1 and e2 are VariableOp expressions, with input columns 27 // // produced by augmentedInput. 28 // 29 type projectBuilder struct { 30 f *Factory 31 projections memo.ProjectionsExpr 32 } 33 34 func (pb *projectBuilder) init(f *Factory) { 35 pb.f = f 36 } 37 38 // empty returns true if there are no synthesized columns (and hence a 39 // projection is not necessary). 40 func (pb *projectBuilder) empty() bool { 41 return len(pb.projections) == 0 42 } 43 44 // add incorporates the given expression as a projection, unless the expression 45 // is already a "bare" variable. Returns a bare variable expression referring to 46 // the synthesized column. 47 func (pb *projectBuilder) add(e opt.ScalarExpr) opt.ScalarExpr { 48 if v, ok := e.(*memo.VariableExpr); ok { 49 // The expression is a bare variable; we don't need to synthesize a column. 50 return v 51 } 52 53 newCol := pb.f.Metadata().AddColumn("", e.DataType()) 54 pb.projections = append(pb.projections, pb.f.ConstructProjectionsItem(e, newCol)) 55 return pb.f.ConstructVariable(newCol) 56 } 57 58 // buildProject creates the ProjectOp (if needed). The ProjectOp passes through 59 // the given passthrough columns and adds any synthesized columns. 60 func (pb *projectBuilder) buildProject(input memo.RelExpr, passthrough opt.ColSet) memo.RelExpr { 61 if pb.empty() { 62 // Avoid creating a Project that does nothing and just gets elided. 63 return input 64 } 65 return pb.f.ConstructProject(input, pb.projections, passthrough) 66 }