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 }