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  }