github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/opt/ordering.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 opt
    12  
    13  import (
    14  	"bytes"
    15  	"fmt"
    16  
    17  	"github.com/cockroachdb/errors"
    18  )
    19  
    20  // OrderingColumn is the ColumnID for a column that is part of an ordering,
    21  // except that it can be negated to indicate a descending ordering on that
    22  // column.
    23  type OrderingColumn int32
    24  
    25  // MakeOrderingColumn initializes an ordering column with a ColumnID and a flag
    26  // indicating whether the direction is descending.
    27  func MakeOrderingColumn(id ColumnID, descending bool) OrderingColumn {
    28  	if descending {
    29  		return OrderingColumn(-id)
    30  	}
    31  	return OrderingColumn(id)
    32  }
    33  
    34  // ID returns the ColumnID for this OrderingColumn.
    35  func (c OrderingColumn) ID() ColumnID {
    36  	if c < 0 {
    37  		return ColumnID(-c)
    38  	}
    39  	return ColumnID(c)
    40  }
    41  
    42  // Ascending returns true if the ordering on this column is ascending.
    43  func (c OrderingColumn) Ascending() bool {
    44  	return c > 0
    45  }
    46  
    47  // Descending returns true if the ordering on this column is descending.
    48  func (c OrderingColumn) Descending() bool {
    49  	return c < 0
    50  }
    51  
    52  func (c OrderingColumn) String() string {
    53  	var buf bytes.Buffer
    54  	c.Format(&buf)
    55  	return buf.String()
    56  }
    57  
    58  // Format prints a string representation to the buffer.
    59  func (c OrderingColumn) Format(buf *bytes.Buffer) {
    60  	if c.Descending() {
    61  		buf.WriteByte('-')
    62  	} else {
    63  		buf.WriteByte('+')
    64  	}
    65  	fmt.Fprintf(buf, "%d", c.ID())
    66  }
    67  
    68  // Ordering defines the order of rows provided or required by an operator. A
    69  // negative value indicates descending order on the column id "-(value)".
    70  type Ordering []OrderingColumn
    71  
    72  // Empty returns true if the ordering is empty or unset.
    73  func (o Ordering) Empty() bool {
    74  	return len(o) == 0
    75  }
    76  
    77  func (o Ordering) String() string {
    78  	var buf bytes.Buffer
    79  	o.Format(&buf)
    80  	return buf.String()
    81  }
    82  
    83  // Format prints a string representation to the buffer.
    84  func (o Ordering) Format(buf *bytes.Buffer) {
    85  	for i, col := range o {
    86  		if i > 0 {
    87  			buf.WriteString(",")
    88  		}
    89  		col.Format(buf)
    90  	}
    91  }
    92  
    93  // ColSet returns the set of column IDs used in the ordering.
    94  func (o Ordering) ColSet() ColSet {
    95  	var colSet ColSet
    96  	for _, col := range o {
    97  		colSet.Add(col.ID())
    98  	}
    99  	return colSet
   100  }
   101  
   102  // Provides returns true if the required ordering is a prefix of this ordering.
   103  func (o Ordering) Provides(required Ordering) bool {
   104  	if len(o) < len(required) {
   105  		return false
   106  	}
   107  
   108  	for i := range required {
   109  		if o[i] != required[i] {
   110  			return false
   111  		}
   112  	}
   113  	return true
   114  }
   115  
   116  // CommonPrefix returns the longest ordering that is a prefix of both orderings.
   117  func (o Ordering) CommonPrefix(other Ordering) Ordering {
   118  	for i := range o {
   119  		if i >= len(other) || o[i] != other[i] {
   120  			return o[:i]
   121  		}
   122  	}
   123  	return o
   124  }
   125  
   126  // Equals returns true if the two orderings are identical.
   127  func (o Ordering) Equals(rhs Ordering) bool {
   128  	if len(o) != len(rhs) {
   129  		return false
   130  	}
   131  
   132  	for i := range o {
   133  		if o[i] != rhs[i] {
   134  			return false
   135  		}
   136  	}
   137  	return true
   138  }
   139  
   140  // OrderingSet is a set of orderings, with the restriction that no ordering
   141  // is a prefix of another ordering in the set.
   142  type OrderingSet []Ordering
   143  
   144  // Copy returns a copy of the set which can be independently modified.
   145  func (os OrderingSet) Copy() OrderingSet {
   146  	res := make(OrderingSet, len(os))
   147  	copy(res, os)
   148  	return res
   149  }
   150  
   151  // Add an ordering to the list, checking whether it is a prefix of another
   152  // ordering (or vice-versa).
   153  func (os *OrderingSet) Add(o Ordering) {
   154  	if len(o) == 0 {
   155  		panic(errors.AssertionFailedf("empty ordering"))
   156  	}
   157  	for i := range *os {
   158  		prefix := (*os)[i].CommonPrefix(o)
   159  		if len(prefix) == len(o) {
   160  			// o is equal to, or a prefix of os[i]. Do nothing.
   161  			return
   162  		}
   163  		if len(prefix) == len((*os)[i]) {
   164  			// os[i] is a prefix of o; replace it.
   165  			(*os)[i] = o
   166  			return
   167  		}
   168  	}
   169  	*os = append(*os, o)
   170  }
   171  
   172  // RestrictToPrefix keeps only the orderings that have the required ordering as
   173  // a prefix.
   174  func (os *OrderingSet) RestrictToPrefix(required Ordering) {
   175  	res := (*os)[:0]
   176  	for _, o := range *os {
   177  		if o.Provides(required) {
   178  			res = append(res, o)
   179  		}
   180  	}
   181  	*os = res
   182  }
   183  
   184  // RestrictToCols keeps only the orderings (or prefixes of them) that refer to
   185  // columns in the given set.
   186  func (os *OrderingSet) RestrictToCols(cols ColSet) {
   187  	old := *os
   188  	*os = old[:0]
   189  	for _, o := range old {
   190  		// Find the longest prefix of the ordering that contains
   191  		// only columns in the set.
   192  		prefix := 0
   193  		for _, c := range o {
   194  			if !cols.Contains(c.ID()) {
   195  				break
   196  			}
   197  			prefix++
   198  		}
   199  		if prefix > 0 {
   200  			// This function appends at most one element; it is ok to operate on the
   201  			// same slice.
   202  			os.Add(o[:prefix])
   203  		}
   204  	}
   205  }
   206  
   207  func (os OrderingSet) String() string {
   208  	var buf bytes.Buffer
   209  	for i, o := range os {
   210  		if i > 0 {
   211  			buf.WriteByte(' ')
   212  		}
   213  		buf.WriteByte('(')
   214  		buf.WriteString(o.String())
   215  		buf.WriteByte(')')
   216  	}
   217  	return buf.String()
   218  }