github.com/dolthub/go-mysql-server@v0.18.0/sql/plan/block.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 "github.com/dolthub/go-mysql-server/sql" 19 ) 20 21 // Block represents a collection of statements that should be executed in sequence. 22 type Block struct { 23 statements []sql.Node 24 rowIterSch sql.Schema // This is set during RowIter, as the schema is unknown until iterating over the statements. 25 } 26 27 // RepresentsBlock is an interface that defines whether a node contains a Block node, or contains multiple child 28 // statements similar to a block node. As a rule of thumb, if a parent node depends upon a child node, either explicitly 29 // or implicitly, then it does not represent a Block. 30 type RepresentsBlock interface { 31 sql.Node 32 implementsRepresentsBlock() 33 } 34 35 // RepresentsLabeledBlock is an interface that defines whether a node represents a Block node, while also carrying a 36 // label that may be referenced by statements within the block (such as LEAVE, ITERATE, etc.). Some statements that use 37 // labels only look for labels on statements that loop (such as LOOP and REPEAT), so there's an additional function 38 // to check whether this also represents a loop. 39 type RepresentsLabeledBlock interface { 40 RepresentsBlock 41 GetBlockLabel(ctx *sql.Context) string 42 RepresentsLoop() bool 43 } 44 45 // RepresentsScope is an interface that defines whether a node represents a new scope. Scopes define boundaries that 46 // are used for variable resolution and control flow modification (via condition handling, etc.). 47 type RepresentsScope interface { 48 RepresentsBlock 49 implementsRepresentsScope() 50 } 51 52 var _ sql.Node = (*Block)(nil) 53 var _ sql.DebugStringer = (*Block)(nil) 54 var _ sql.CollationCoercible = (*Block)(nil) 55 var _ RepresentsBlock = (*Block)(nil) 56 57 // NewBlock creates a new *Block node. 58 func NewBlock(statements []sql.Node) *Block { 59 return &Block{statements: statements} 60 } 61 62 // Resolved implements the sql.Node interface. 63 func (b *Block) Resolved() bool { 64 for _, s := range b.statements { 65 if !s.Resolved() { 66 return false 67 } 68 } 69 return true 70 } 71 72 func (b *Block) IsReadOnly() bool { 73 for _, n := range b.statements { 74 if !n.IsReadOnly() { 75 return false 76 } 77 } 78 return true 79 } 80 81 // String implements the sql.Node interface. 82 func (b *Block) String() string { 83 p := sql.NewTreePrinter() 84 _ = p.WriteNode("BLOCK") 85 var children []string 86 for _, s := range b.statements { 87 children = append(children, s.String()) 88 } 89 _ = p.WriteChildren(children...) 90 return p.String() 91 } 92 93 // DebugString implements the sql.DebugStringer interface. 94 func (b *Block) DebugString() string { 95 p := sql.NewTreePrinter() 96 _ = p.WriteNode("BLOCK") 97 var children []string 98 for _, s := range b.statements { 99 children = append(children, sql.DebugString(s)) 100 } 101 _ = p.WriteChildren(children...) 102 return p.String() 103 } 104 105 // Schema implements the sql.Node interface. 106 func (b *Block) Schema() sql.Schema { 107 return b.rowIterSch 108 } 109 110 func (b *Block) SetSchema(sch sql.Schema) { 111 b.rowIterSch = sch 112 } 113 114 // Children implements the sql.Node interface. 115 func (b *Block) Children() []sql.Node { 116 return b.statements 117 } 118 119 // WithChildren implements the sql.Node interface. 120 func (b *Block) WithChildren(children ...sql.Node) (sql.Node, error) { 121 nb := *b 122 nb.statements = children 123 return &nb, nil 124 } 125 126 // CheckPrivileges implements the interface sql.Node. 127 func (b *Block) CheckPrivileges(ctx *sql.Context, opChecker sql.PrivilegedOperationChecker) bool { 128 for _, statement := range b.statements { 129 if !statement.CheckPrivileges(ctx, opChecker) { 130 return false 131 } 132 } 133 return true 134 } 135 136 // CollationCoercibility implements the interface sql.CollationCoercible. 137 func (b *Block) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) { 138 // The last SELECT used in the block takes priority 139 for i := len(b.statements) - 1; i >= 0; i-- { 140 if NodeRepresentsSelect(b.statements[i]) { 141 return sql.GetCoercibility(ctx, b.statements[i]) 142 } 143 } 144 // If the block is empty then we return an ignorable coercibility 145 if len(b.statements) == 0 { 146 return sql.Collation_binary, 7 147 } 148 // If none of the above applies, we return the coercibility of the last statement in the block 149 return sql.GetCoercibility(ctx, b.statements[len(b.statements)-1]) 150 } 151 152 // implementsRepresentsBlock implements the RepresentsBlock interface. 153 func (b *Block) implementsRepresentsBlock() {}