github.com/dolthub/go-mysql-server@v0.18.0/sql/plan/loop.go (about) 1 // Copyright 2022 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 "github.com/dolthub/go-mysql-server/sql/expression" 20 "github.com/dolthub/go-mysql-server/sql/types" 21 ) 22 23 // Loop represents the LOOP statement, which loops over a set of statements. 24 type Loop struct { 25 Label string 26 Condition sql.Expression // We continue looping until the condition returns false 27 OnceBeforeEval bool // Whether to run through the statements first before evaluating the condition 28 *Block 29 } 30 31 var _ sql.Node = (*Loop)(nil) 32 var _ sql.DebugStringer = (*Loop)(nil) 33 var _ sql.Expressioner = (*Loop)(nil) 34 var _ sql.CollationCoercible = (*Loop)(nil) 35 var _ RepresentsLabeledBlock = (*Loop)(nil) 36 37 // NewLoop returns a new *Loop node. 38 func NewLoop(label string, block *Block) *Loop { 39 return &Loop{ 40 Label: label, 41 Condition: expression.NewLiteral(true, types.Boolean), 42 OnceBeforeEval: true, 43 Block: block, 44 } 45 } 46 47 // String implements the interface sql.Node. 48 func (l *Loop) String() string { 49 label := "" 50 if len(l.Label) > 0 { 51 label = l.Label + ": " 52 } 53 p := sql.NewTreePrinter() 54 _ = p.WriteNode(label + "LOOP") 55 var children []string 56 for _, s := range l.statements { 57 children = append(children, s.String()) 58 } 59 _ = p.WriteChildren(children...) 60 return p.String() 61 } 62 63 // DebugString implements the interface sql.DebugStringer. 64 func (l *Loop) DebugString() string { 65 label := "" 66 if len(l.Label) > 0 { 67 label = l.Label + ": " 68 } 69 p := sql.NewTreePrinter() 70 _ = p.WriteNode(label + ": LOOP") 71 var children []string 72 for _, s := range l.statements { 73 children = append(children, sql.DebugString(s)) 74 } 75 _ = p.WriteChildren(children...) 76 return p.String() 77 } 78 79 // Resolved implements the interface sql.Node. 80 func (l *Loop) Resolved() bool { 81 return l.Condition.Resolved() && l.Block.Resolved() 82 } 83 84 // WithChildren implements the interface sql.Node. 85 func (l *Loop) WithChildren(children ...sql.Node) (sql.Node, error) { 86 return &Loop{ 87 Label: l.Label, 88 Condition: l.Condition, 89 OnceBeforeEval: l.OnceBeforeEval, 90 Block: NewBlock(children), 91 }, nil 92 } 93 94 // Expressions implements the interface sql.Node. 95 func (l *Loop) Expressions() []sql.Expression { 96 return []sql.Expression{l.Condition} 97 } 98 99 // WithExpressions implements the interface sql.Node. 100 func (l *Loop) WithExpressions(exprs ...sql.Expression) (sql.Node, error) { 101 if len(exprs) != 1 { 102 return nil, sql.ErrInvalidChildrenNumber.New(l, len(exprs), 1) 103 } 104 105 return &Loop{ 106 Label: l.Label, 107 Condition: exprs[0], 108 OnceBeforeEval: l.OnceBeforeEval, 109 Block: l.Block, 110 }, nil 111 } 112 113 // CheckPrivileges implements the interface sql.Node. 114 func (l *Loop) CheckPrivileges(ctx *sql.Context, opChecker sql.PrivilegedOperationChecker) bool { 115 return l.Block.CheckPrivileges(ctx, opChecker) 116 } 117 118 // CollationCoercibility implements the interface sql.CollationCoercible. 119 func (l *Loop) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) { 120 return l.Block.CollationCoercibility(ctx) 121 } 122 123 // GetBlockLabel implements the interface RepresentsLabeledBlock. 124 func (l *Loop) GetBlockLabel(ctx *sql.Context) string { 125 return l.Label 126 } 127 128 // RepresentsLoop implements the interface RepresentsLabeledBlock. 129 func (l *Loop) RepresentsLoop() bool { 130 return true 131 }