github.com/dolthub/go-mysql-server@v0.18.0/sql/plan/subqueryalias.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  
    20  	"github.com/dolthub/go-mysql-server/sql"
    21  )
    22  
    23  // SubqueryAlias is a node that gives a subquery a name.
    24  type SubqueryAlias struct {
    25  	UnaryNode
    26  	ColumnNames    []string
    27  	name           string
    28  	TextDefinition string
    29  	// OuterScopeVisibility is true when a SubqueryAlias (i.e. derived table) is contained in a subquery
    30  	// expression and is eligible to have visibility to outer scopes of the query.
    31  	OuterScopeVisibility bool
    32  	Correlated           sql.ColSet
    33  	Volatile             bool
    34  	CacheableCTESource   bool
    35  	IsLateral            bool
    36  	ScopeMapping         map[sql.ColumnId]sql.Expression
    37  	id                   sql.TableId
    38  	cols                 sql.ColSet
    39  }
    40  
    41  var _ sql.Node = (*SubqueryAlias)(nil)
    42  var _ sql.CollationCoercible = (*SubqueryAlias)(nil)
    43  var _ sql.RenameableNode = (*SubqueryAlias)(nil)
    44  
    45  // NewSubqueryAlias creates a new SubqueryAlias node.
    46  func NewSubqueryAlias(name, textDefinition string, node sql.Node) *SubqueryAlias {
    47  	return &SubqueryAlias{
    48  		UnaryNode:            UnaryNode{Child: node},
    49  		name:                 name,
    50  		TextDefinition:       textDefinition,
    51  		OuterScopeVisibility: false,
    52  	}
    53  }
    54  
    55  // WithId implements sql.TableIdNode
    56  func (sq *SubqueryAlias) WithId(id sql.TableId) TableIdNode {
    57  	ret := *sq
    58  	ret.id = id
    59  	return &ret
    60  }
    61  
    62  // Id implements sql.TableIdNode
    63  func (sq *SubqueryAlias) Id() sql.TableId {
    64  	return sq.id
    65  }
    66  
    67  // WithColumns implements sql.TableIdNode
    68  func (sq *SubqueryAlias) WithColumns(set sql.ColSet) TableIdNode {
    69  	ret := *sq
    70  	ret.cols = set
    71  	return &ret
    72  }
    73  
    74  // Columns implements sql.TableIdNode
    75  func (sq *SubqueryAlias) Columns() sql.ColSet {
    76  	return sq.cols
    77  }
    78  
    79  // AsView returns the view wrapper for this subquery
    80  func (sq *SubqueryAlias) AsView(createViewStmt string) *sql.View {
    81  	return sql.NewView(sq.Name(), sq, sq.TextDefinition, createViewStmt)
    82  }
    83  
    84  // Name implements the Table interface.
    85  func (sq *SubqueryAlias) Name() string { return sq.name }
    86  
    87  func (sq *SubqueryAlias) WithName(n string) sql.Node {
    88  	ret := *sq
    89  	ret.name = n
    90  	return &ret
    91  }
    92  
    93  func (sq *SubqueryAlias) IsReadOnly() bool {
    94  	return sq.Child.IsReadOnly()
    95  }
    96  
    97  // Schema implements the Node interface.
    98  func (sq *SubqueryAlias) Schema() sql.Schema {
    99  	childSchema := sq.Child.Schema()
   100  	schema := make(sql.Schema, len(childSchema))
   101  	for i, col := range childSchema {
   102  		c := *col
   103  		c.Source = sq.name
   104  		if len(sq.ColumnNames) > 0 {
   105  			c.Name = sq.ColumnNames[i]
   106  		}
   107  		schema[i] = &c
   108  	}
   109  	return schema
   110  }
   111  
   112  // WithChildren implements the Node interface.
   113  func (sq *SubqueryAlias) WithChildren(children ...sql.Node) (sql.Node, error) {
   114  	if len(children) != 1 {
   115  		return nil, sql.ErrInvalidChildrenNumber.New(sq, len(children), 1)
   116  	}
   117  
   118  	nn := *sq
   119  	nn.Child = children[0]
   120  	return &nn, nil
   121  }
   122  
   123  // CheckPrivileges implements the interface sql.Node.
   124  func (sq *SubqueryAlias) CheckPrivileges(ctx *sql.Context, opChecker sql.PrivilegedOperationChecker) bool {
   125  	return sq.Child.CheckPrivileges(ctx, opChecker)
   126  }
   127  
   128  // CollationCoercibility implements the interface sql.CollationCoercible.
   129  func (sq *SubqueryAlias) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) {
   130  	return sql.GetCoercibility(ctx, sq.Child)
   131  }
   132  
   133  func (sq *SubqueryAlias) WithChild(n sql.Node) *SubqueryAlias {
   134  	ret := *sq
   135  	ret.Child = n
   136  	return &ret
   137  }
   138  
   139  func (sq *SubqueryAlias) CanCacheResults() bool {
   140  	return sq.Correlated.Empty() && !sq.Volatile
   141  }
   142  
   143  func (sq *SubqueryAlias) WithCorrelated(cols sql.ColSet) *SubqueryAlias {
   144  	ret := *sq
   145  	ret.Correlated = cols
   146  	return &ret
   147  }
   148  
   149  func (sq *SubqueryAlias) WithVolatile(v bool) *SubqueryAlias {
   150  	ret := *sq
   151  	ret.Volatile = v
   152  	return &ret
   153  }
   154  
   155  func (sq *SubqueryAlias) WithScopeMapping(cols map[sql.ColumnId]sql.Expression) *SubqueryAlias {
   156  	ret := *sq
   157  	ret.ScopeMapping = cols
   158  	return &ret
   159  }
   160  
   161  // Opaque implements the OpaqueNode interface.
   162  func (sq *SubqueryAlias) Opaque() bool {
   163  	return true
   164  }
   165  
   166  func (sq *SubqueryAlias) String() string {
   167  	pr := sql.NewTreePrinter()
   168  	_ = pr.WriteNode("SubqueryAlias")
   169  	children := make([]string, 5)
   170  	children[0] = fmt.Sprintf("name: %s", sq.name)
   171  	children[1] = fmt.Sprintf("outerVisibility: %t", sq.OuterScopeVisibility)
   172  	children[2] = fmt.Sprintf("isLateral: %t", sq.IsLateral)
   173  	children[3] = fmt.Sprintf("cacheable: %t", sq.CanCacheResults())
   174  	children[4] = sq.Child.String()
   175  	_ = pr.WriteChildren(children...)
   176  	return pr.String()
   177  }
   178  
   179  func (sq *SubqueryAlias) DebugString() string {
   180  	pr := sql.NewTreePrinter()
   181  	_ = pr.WriteNode("SubqueryAlias")
   182  	children := make([]string, 7)
   183  	children[0] = fmt.Sprintf("name: %s", sq.name)
   184  	children[1] = fmt.Sprintf("outerVisibility: %t", sq.OuterScopeVisibility)
   185  	children[2] = fmt.Sprintf("isLateral: %t", sq.IsLateral)
   186  	children[3] = fmt.Sprintf("cacheable: %t", sq.CanCacheResults())
   187  	children[4] = fmt.Sprintf("colSet: %s", sq.Columns())
   188  	children[5] = fmt.Sprintf("tableId: %d", sq.Id())
   189  	children[6] = sql.DebugString(sq.Child)
   190  	_ = pr.WriteChildren(children...)
   191  	return pr.String()
   192  }
   193  
   194  func (sq *SubqueryAlias) WithColumnNames(columns []string) *SubqueryAlias {
   195  	ret := *sq
   196  	ret.ColumnNames = columns
   197  	return &ret
   198  }