github.com/dolthub/go-mysql-server@v0.18.0/sql/plan/project.go (about) 1 // Copyright 2020-2021 Dolthub, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package plan 16 17 import ( 18 "fmt" 19 "strings" 20 21 "github.com/dolthub/go-mysql-server/sql" 22 "github.com/dolthub/go-mysql-server/sql/expression" 23 "github.com/dolthub/go-mysql-server/sql/transform" 24 ) 25 26 // Project is a projection of certain expression from the children node. 27 type Project struct { 28 UnaryNode 29 // Expression projected. 30 Projections []sql.Expression 31 } 32 33 var _ sql.Expressioner = (*Project)(nil) 34 var _ sql.Node = (*Project)(nil) 35 var _ sql.Projector = (*Project)(nil) 36 var _ sql.CollationCoercible = (*Project)(nil) 37 38 // NewProject creates a new projection. 39 func NewProject(expressions []sql.Expression, child sql.Node) *Project { 40 return &Project{ 41 UnaryNode: UnaryNode{child}, 42 Projections: expressions, 43 } 44 } 45 46 // Schema implements the Node interface. 47 func (p *Project) Schema() sql.Schema { 48 var s = make(sql.Schema, len(p.Projections)) 49 for i, e := range p.Projections { 50 s[i] = transform.ExpressionToColumn(e, AliasSubqueryString(e)) 51 } 52 return s 53 } 54 55 // Resolved implements the Resolvable interface. 56 func (p *Project) Resolved() bool { 57 return p.UnaryNode.Child.Resolved() && 58 expression.ExpressionsResolved(p.Projections...) 59 } 60 61 func (p *Project) IsReadOnly() bool { 62 return p.Child.IsReadOnly() 63 } 64 65 // Describe implements the sql.Describable interface. 66 func (p *Project) Describe(options sql.DescribeOptions) string { 67 pr := sql.NewTreePrinter() 68 _ = pr.WriteNode("Project") 69 var exprs = make([]string, len(p.Projections)) 70 for i, expr := range p.Projections { 71 exprs[i] = sql.Describe(expr, options) 72 } 73 columns := fmt.Sprintf("columns: [%s]", strings.Join(exprs, ", ")) 74 _ = pr.WriteChildren(columns, sql.Describe(p.Child, options)) 75 return pr.String() 76 } 77 78 // String implements the fmt.Stringer interface. 79 func (p *Project) String() string { 80 return p.Describe(sql.DescribeOptions{ 81 Analyze: false, 82 Estimates: false, 83 Debug: false, 84 }) 85 } 86 87 // DebugString implements the sql.DebugStringer interface. 88 func (p *Project) DebugString() string { 89 return p.Describe(sql.DescribeOptions{ 90 Analyze: false, 91 Estimates: false, 92 Debug: true, 93 }) 94 } 95 96 // Expressions implements the Expressioner interface. 97 func (p *Project) Expressions() []sql.Expression { 98 return p.Projections 99 } 100 101 // ProjectedExprs implements sql.Projector 102 func (p *Project) ProjectedExprs() []sql.Expression { 103 return p.Projections 104 } 105 106 // WithChildren implements the Node interface. 107 func (p *Project) WithChildren(children ...sql.Node) (sql.Node, error) { 108 if len(children) != 1 { 109 return nil, sql.ErrInvalidChildrenNumber.New(p, len(children), 1) 110 } 111 112 return NewProject(p.Projections, children[0]), nil 113 } 114 115 // CheckPrivileges implements the interface sql.Node. 116 func (p *Project) CheckPrivileges(ctx *sql.Context, opChecker sql.PrivilegedOperationChecker) bool { 117 return p.Child.CheckPrivileges(ctx, opChecker) 118 } 119 120 // CollationCoercibility implements the interface sql.CollationCoercible. 121 func (p *Project) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) { 122 return sql.GetCoercibility(ctx, p.Child) 123 } 124 125 // WithExpressions implements the Expressioner interface. 126 func (p *Project) WithExpressions(exprs ...sql.Expression) (sql.Node, error) { 127 if len(exprs) != len(p.Projections) { 128 return nil, sql.ErrInvalidChildrenNumber.New(p, len(exprs), len(p.Projections)) 129 } 130 131 return NewProject(exprs, p.Child), nil 132 }