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() {}