github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/opt/props/physical/required.go (about)

     1  // Copyright 2018 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  package physical
    12  
    13  import (
    14  	"bytes"
    15  	"fmt"
    16  
    17  	"github.com/cockroachdb/cockroach/pkg/sql/opt"
    18  )
    19  
    20  // Required properties are interesting characteristics of an expression that
    21  // impact its layout, presentation, or location, but not its logical content.
    22  // Examples include row order, column naming, and data distribution (physical
    23  // location of data ranges). Physical properties exist outside of the relational
    24  // algebra, and arise from both the SQL query itself (e.g. the non-relational
    25  // ORDER BY operator) and by the selection of specific implementations during
    26  // optimization (e.g. a merge join requires the inputs to be sorted in a
    27  // particular order).
    28  //
    29  // Required properties are derived top-to-bottom - there is a required physical
    30  // property on the root, and each expression can require physical properties on
    31  // one or more of its operands. When an expression is optimized, it is always
    32  // with respect to a particular set of required physical properties. The goal
    33  // is to find the lowest cost expression that provides those properties while
    34  // still remaining logically equivalent.
    35  type Required struct {
    36  	// Presentation specifies the naming, membership (including duplicates),
    37  	// and order of result columns. If Presentation is not defined, then no
    38  	// particular column presentation is required or provided.
    39  	Presentation Presentation
    40  
    41  	// Ordering specifies the sort order of result rows. Rows can be sorted by
    42  	// one or more columns, each of which can be sorted in either ascending or
    43  	// descending order. If Ordering is not defined, then no particular ordering
    44  	// is required or provided.
    45  	Ordering OrderingChoice
    46  
    47  	// LimitHint specifies a "soft limit" to the number of result rows that may
    48  	// be required of the expression. If requested, an expression will still need
    49  	// to return all result rows, but it can be optimized based on the assumption
    50  	// that only the hinted number of rows will be needed.
    51  	// A LimitHint of 0 indicates "no limit". The LimitHint is an intermediate
    52  	// float64 representation, and can be converted to an integer number of rows
    53  	// using math.Ceil.
    54  	LimitHint float64
    55  }
    56  
    57  // MinRequired are the default physical properties that require nothing and
    58  // provide nothing.
    59  var MinRequired = &Required{}
    60  
    61  // Defined is true if any physical property is defined. If none is defined, then
    62  // this is an instance of MinRequired.
    63  func (p *Required) Defined() bool {
    64  	return !p.Presentation.Any() || !p.Ordering.Any() || p.LimitHint != 0
    65  }
    66  
    67  // ColSet returns the set of columns used by any of the physical properties.
    68  func (p *Required) ColSet() opt.ColSet {
    69  	colSet := p.Ordering.ColSet()
    70  	for _, col := range p.Presentation {
    71  		colSet.Add(col.ID)
    72  	}
    73  	return colSet
    74  }
    75  
    76  func (p *Required) String() string {
    77  	var buf bytes.Buffer
    78  	output := func(name string, fn func(*bytes.Buffer)) {
    79  		if buf.Len() != 0 {
    80  			buf.WriteByte(' ')
    81  		}
    82  		buf.WriteByte('[')
    83  		buf.WriteString(name)
    84  		buf.WriteString(": ")
    85  		fn(&buf)
    86  		buf.WriteByte(']')
    87  	}
    88  
    89  	if !p.Presentation.Any() {
    90  		output("presentation", p.Presentation.format)
    91  	}
    92  	if !p.Ordering.Any() {
    93  		output("ordering", p.Ordering.Format)
    94  	}
    95  	if p.LimitHint != 0 {
    96  		output("limit hint", func(buf *bytes.Buffer) { fmt.Fprintf(buf, "%.2f", p.LimitHint) })
    97  	}
    98  
    99  	// Handle empty properties case.
   100  	if buf.Len() == 0 {
   101  		return "[]"
   102  	}
   103  	return buf.String()
   104  }
   105  
   106  // Equals returns true if the two physical properties are identical.
   107  func (p *Required) Equals(rhs *Required) bool {
   108  	return p.Presentation.Equals(rhs.Presentation) && p.Ordering.Equals(&rhs.Ordering) && p.LimitHint == rhs.LimitHint
   109  }
   110  
   111  // Presentation specifies the naming, membership (including duplicates), and
   112  // order of result columns that are required of or provided by an operator.
   113  // While it cannot add unique columns, Presentation can rename, reorder,
   114  // duplicate and discard columns. If Presentation is not defined, then no
   115  // particular column presentation is required or provided. For example:
   116  //   a.y:2 a.x:1 a.y:2 column1:3
   117  type Presentation []opt.AliasedColumn
   118  
   119  // Any is true if any column presentation is allowed or can be provided.
   120  func (p Presentation) Any() bool {
   121  	return p == nil
   122  }
   123  
   124  // Equals returns true iff this presentation exactly matches the given
   125  // presentation.
   126  func (p Presentation) Equals(rhs Presentation) bool {
   127  	// The 0 column presentation is not the same as the nil presentation.
   128  	if p.Any() != rhs.Any() {
   129  		return false
   130  	}
   131  	if len(p) != len(rhs) {
   132  		return false
   133  	}
   134  
   135  	for i := 0; i < len(p); i++ {
   136  		if p[i] != rhs[i] {
   137  			return false
   138  		}
   139  	}
   140  	return true
   141  }
   142  
   143  func (p Presentation) String() string {
   144  	var buf bytes.Buffer
   145  	p.format(&buf)
   146  	return buf.String()
   147  }
   148  
   149  func (p Presentation) format(buf *bytes.Buffer) {
   150  	for i, col := range p {
   151  		if i > 0 {
   152  			buf.WriteString(",")
   153  		}
   154  		fmt.Fprintf(buf, "%s:%d", col.Alias, col.ID)
   155  	}
   156  }