github.com/dolthub/go-mysql-server@v0.18.0/sql/plan/exchange.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  	errors "gopkg.in/src-d/go-errors.v1"
    21  
    22  	"github.com/dolthub/go-mysql-server/sql"
    23  )
    24  
    25  // ErrNoPartitionable is returned when no Partitionable node is found
    26  // in the Exchange tree.
    27  var ErrNoPartitionable = errors.NewKind("no partitionable node found in exchange tree")
    28  
    29  // Exchange is a node that can parallelize the underlying tree iterating
    30  // partitions concurrently.
    31  type Exchange struct {
    32  	UnaryNode
    33  	Parallelism int
    34  }
    35  
    36  var _ sql.Node = (*Exchange)(nil)
    37  var _ sql.CollationCoercible = (*Exchange)(nil)
    38  
    39  // NewExchange creates a new Exchange node.
    40  func NewExchange(
    41  	parallelism int,
    42  	child sql.Node,
    43  ) *Exchange {
    44  	return &Exchange{
    45  		UnaryNode:   UnaryNode{Child: child},
    46  		Parallelism: parallelism,
    47  	}
    48  }
    49  
    50  func (e *Exchange) String() string {
    51  	p := sql.NewTreePrinter()
    52  	_ = p.WriteNode("Exchange")
    53  	_ = p.WriteChildren(e.Child.String())
    54  	return p.String()
    55  }
    56  
    57  func (e *Exchange) DebugString() string {
    58  	p := sql.NewTreePrinter()
    59  	_ = p.WriteNode("Exchange(parallelism=%d)", e.Parallelism)
    60  	_ = p.WriteChildren(sql.DebugString(e.Child))
    61  	return p.String()
    62  }
    63  
    64  func (e *Exchange) IsReadOnly() bool {
    65  	return e.Child.IsReadOnly()
    66  }
    67  
    68  // WithChildren implements the Node interface.
    69  func (e *Exchange) WithChildren(children ...sql.Node) (sql.Node, error) {
    70  	if len(children) != 1 {
    71  		return nil, sql.ErrInvalidChildrenNumber.New(e, len(children), 1)
    72  	}
    73  
    74  	return NewExchange(e.Parallelism, children[0]), nil
    75  }
    76  
    77  // CheckPrivileges implements the interface sql.Node.
    78  func (e *Exchange) CheckPrivileges(ctx *sql.Context, opChecker sql.PrivilegedOperationChecker) bool {
    79  	return e.Child.CheckPrivileges(ctx, opChecker)
    80  }
    81  
    82  // CollationCoercibility implements the interface sql.CollationCoercible.
    83  func (e *Exchange) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) {
    84  	return sql.GetCoercibility(ctx, e.Child)
    85  }
    86  
    87  type ExchangePartition struct {
    88  	sql.Partition
    89  	Table sql.Table
    90  }
    91  
    92  var _ sql.Node = (*ExchangePartition)(nil)
    93  
    94  func (p *ExchangePartition) String() string {
    95  	return fmt.Sprintf("Partition(%s)", string(p.Key()))
    96  }
    97  
    98  func (ExchangePartition) Children() []sql.Node { return nil }
    99  
   100  func (ExchangePartition) Resolved() bool   { return true }
   101  func (ExchangePartition) IsReadOnly() bool { return true }
   102  
   103  func (p *ExchangePartition) Schema() sql.Schema {
   104  	return p.Table.Schema()
   105  }
   106  
   107  // WithChildren implements the Node interface.
   108  func (p *ExchangePartition) WithChildren(children ...sql.Node) (sql.Node, error) {
   109  	if len(children) != 0 {
   110  		return nil, sql.ErrInvalidChildrenNumber.New(p, len(children), 0)
   111  	}
   112  
   113  	return p, nil
   114  }
   115  
   116  // CheckPrivileges implements the interface sql.Node.
   117  func (p *ExchangePartition) CheckPrivileges(ctx *sql.Context, opChecker sql.PrivilegedOperationChecker) bool {
   118  	if node, ok := p.Table.(sql.Node); ok {
   119  		return node.CheckPrivileges(ctx, opChecker)
   120  	}
   121  	// If the table is not a TableNode or other such node, then I guess we'll return true as to not fail.
   122  	// This may not be the correct behavior though, as it's just a guess.
   123  	return true
   124  }
   125  
   126  // CollationCoercibility implements the interface sql.CollationCoercible.
   127  func (p *ExchangePartition) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) {
   128  	// This is inspired by CheckPrivileges, although it may not be the desired behavior in all circumstances
   129  	if node, ok := p.Table.(sql.Node); ok {
   130  		return sql.GetCoercibility(ctx, node)
   131  	}
   132  	return sql.Collation_binary, 7
   133  }