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  }