github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/opt/props/physical/ordering_choice.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  	"regexp"
    17  	"strconv"
    18  	"strings"
    19  	"sync"
    20  
    21  	"github.com/cockroachdb/cockroach/pkg/sql/opt"
    22  	"github.com/cockroachdb/cockroach/pkg/sql/opt/props"
    23  	"github.com/cockroachdb/errors"
    24  )
    25  
    26  // OrderingChoice defines the set of possible row orderings that are provided or
    27  // required by an operator. An OrderingChoice consists of two parts: an ordered
    28  // sequence of equivalent column groups and a set of optional columns. Together,
    29  // these parts specify a simple pattern that can match one or more candidate
    30  // orderings. Here are some examples:
    31  //
    32  //   +1                  ORDER BY a
    33  //   +1,-2               ORDER BY a,b DESC
    34  //   +(1|2)              ORDER BY a        | ORDER BY b
    35  //   +(1|2),+3           ORDER BY a,c      | ORDER BY b, c
    36  //   -(3|4),+5 opt(1,2)  ORDER BY c DESC,e | ORDER BY a,d DESC,b DESC,e | ...
    37  //
    38  // Each column in the ordering sequence forms the corresponding column of the
    39  // sort key, from most significant to least significant. Each column has a sort
    40  // direction, either ascending or descending. The relation is ordered by the
    41  // first column; rows that have the same value are then ordered by the second
    42  // column; rows that still have the same value are ordered by the third column,
    43  // and so on.
    44  //
    45  // Sometimes multiple columns in the relation have equivalent values. The
    46  // OrderingChoiceColumn stores these columns in a group; any of the columns in
    47  // the group can be used to form the corresponding column in the sort key. The
    48  // equivalent group columns come from SQL expressions like:
    49  //
    50  //   a=b
    51  //
    52  // The optional column set contains columns that can appear anywhere (or
    53  // nowhere) in the ordering. Optional columns come from SQL expressions like:
    54  //
    55  //   a=1
    56  //
    57  // Another case for optional columns is when we are grouping along a set of
    58  // columns and only care about the intra-group ordering.
    59  //
    60  // The optional columns can be interleaved anywhere in the sequence of ordering
    61  // columns, as they have no effect on the ordering.
    62  type OrderingChoice struct {
    63  	// Optional is the set of columns that can appear at any position in the
    64  	// ordering. Columns in Optional must not appear in the Columns sequence.
    65  	// In addition, if Columns is empty, then Optional must be as well.
    66  	// After initial construction, Optional is immutable. To update, replace
    67  	// with a different set containing the desired columns.
    68  	Optional opt.ColSet
    69  
    70  	// Columns is the sequence of equivalent column groups that can be used to
    71  	// form each column in the sort key. Columns must not appear in the Optional
    72  	// set. The array memory is owned by this struct, and should not be copied
    73  	// to another OrderingChoice unless both are kept immutable.
    74  	Columns []OrderingColumnChoice
    75  }
    76  
    77  // OrderingColumnChoice specifies the set of columns which can form one of the
    78  // columns in the sort key, as well as the direction of that column (ascending
    79  // or descending).
    80  type OrderingColumnChoice struct {
    81  	// Group is a set of equivalent columns, any of which can be used to form a
    82  	// column in the sort key. After initial construction, Group is immutable.
    83  	// To update, replace with a different set containing the desired columns.
    84  	Group opt.ColSet
    85  
    86  	// Descending is true if the sort key column is ordered from highest to
    87  	// lowest. Otherwise, it's ordered from lowest to highest.
    88  	Descending bool
    89  }
    90  
    91  const (
    92  	colChoiceRegexStr = `(?:\((\d+(?:\|\d+)*)\))`
    93  	ordColRegexStr    = `^(?:(?:\+|\-)(?:(\d+)|` + colChoiceRegexStr + `))$`
    94  	colListRegexStr   = `(\d+(?:,\d+)*)`
    95  	optRegexStr       = `^\s*([\S]+)?\s*(?:opt\(` + colListRegexStr + `\))?\s*$`
    96  )
    97  
    98  var once sync.Once
    99  var optRegex, ordColRegex *regexp.Regexp
   100  
   101  // ParseOrderingChoice parses the string representation of an OrderingChoice for
   102  // testing purposes. Here are some examples of the string format:
   103  //
   104  //   +1
   105  //   -(1|2),+3
   106  //   +(1|2),+3 opt(5,6)
   107  //
   108  // The input string is expected to be valid; ParseOrderingChoice will panic if
   109  // it is not.
   110  func ParseOrderingChoice(s string) OrderingChoice {
   111  	once.Do(func() {
   112  		optRegex = regexp.MustCompile(optRegexStr)
   113  		ordColRegex = regexp.MustCompile(ordColRegexStr)
   114  	})
   115  
   116  	var ordering OrderingChoice
   117  
   118  	// Separate string into column sequence and optional column parts:
   119  	//   +(1|2),+3 opt(5,6)
   120  	//     matches[1]: +(1|2),+3
   121  	//     matches[2]: opt(5,6)
   122  	matches := optRegex.FindStringSubmatch(s)
   123  	if matches == nil {
   124  		panic(errors.AssertionFailedf("could not parse ordering choice: %s", s))
   125  	}
   126  
   127  	// Handle Any case.
   128  	if len(matches[1]) == 0 {
   129  		return OrderingChoice{}
   130  	}
   131  
   132  	// Split column sequence by comma:
   133  	//   +(1|2),+3:
   134  	//     +(1|2)
   135  	//     +3
   136  	for _, ordColStr := range strings.Split(matches[1], ",") {
   137  		// Parse one item in the column sequence:
   138  		//   +(1|2):
   139  		//     matches[1]: <empty>
   140  		//     matches[2]: 1|2
   141  		//
   142  		//   +3:
   143  		//     matches[1]: 3
   144  		//     matches[2]: <empty>
   145  		ordColMatches := ordColRegex.FindStringSubmatch(ordColStr)
   146  
   147  		// First character is the direction indicator.
   148  		var colChoice OrderingColumnChoice
   149  		colChoice.Descending = strings.HasPrefix(ordColStr, "-")
   150  
   151  		if len(ordColMatches[1]) != 0 {
   152  			// Single column in equivalence group.
   153  			id, _ := strconv.Atoi(ordColMatches[1])
   154  			colChoice.Group.Add(opt.ColumnID(id))
   155  		} else {
   156  			// Split multiple columns in equivalence group by pipe:
   157  			//   1|2:
   158  			//     1
   159  			//     2
   160  			for _, idStr := range strings.Split(ordColMatches[2], "|") {
   161  				id, _ := strconv.Atoi(idStr)
   162  				colChoice.Group.Add(opt.ColumnID(id))
   163  			}
   164  		}
   165  
   166  		ordering.Columns = append(ordering.Columns, colChoice)
   167  	}
   168  
   169  	// Parse any optional columns by splitting by comma:
   170  	//   opt(5,6):
   171  	//     5
   172  	//     6
   173  	if len(matches[2]) != 0 {
   174  		for _, idStr := range strings.Split(matches[2], ",") {
   175  			id, _ := strconv.Atoi(idStr)
   176  			ordering.Optional.Add(opt.ColumnID(id))
   177  		}
   178  	}
   179  
   180  	return ordering
   181  }
   182  
   183  // ParseOrdering parses a simple opt.Ordering; for example: "+1,-3".
   184  //
   185  // The input string is expected to be valid; ParseOrdering will panic if it is
   186  // not.
   187  func ParseOrdering(str string) opt.Ordering {
   188  	prov := ParseOrderingChoice(str)
   189  	if !prov.Optional.Empty() {
   190  		panic(errors.AssertionFailedf("invalid ordering %s", str))
   191  	}
   192  	for i := range prov.Columns {
   193  		if prov.Columns[i].Group.Len() != 1 {
   194  			panic(errors.AssertionFailedf("invalid ordering %s", str))
   195  		}
   196  	}
   197  	return prov.ToOrdering()
   198  }
   199  
   200  // Any is true if this instance allows any ordering (any length, any columns).
   201  func (oc *OrderingChoice) Any() bool {
   202  	return len(oc.Columns) == 0
   203  }
   204  
   205  // FromOrdering sets this OrderingChoice to the given opt.Ordering.
   206  func (oc *OrderingChoice) FromOrdering(ord opt.Ordering) {
   207  	oc.Optional = opt.ColSet{}
   208  	oc.Columns = make([]OrderingColumnChoice, len(ord))
   209  	for i := range ord {
   210  		oc.Columns[i].Group.Add(ord[i].ID())
   211  		oc.Columns[i].Descending = ord[i].Descending()
   212  	}
   213  }
   214  
   215  // FromOrderingWithOptCols sets this OrderingChoice to the given opt.Ordering
   216  // and with the given optional columns. Any optional columns in the given
   217  // ordering are ignored.
   218  func (oc *OrderingChoice) FromOrderingWithOptCols(ord opt.Ordering, optCols opt.ColSet) {
   219  	oc.Optional = optCols.Copy()
   220  	oc.Columns = make([]OrderingColumnChoice, 0, len(ord))
   221  	for i := range ord {
   222  		if !oc.Optional.Contains(ord[i].ID()) {
   223  			oc.Columns = append(oc.Columns, OrderingColumnChoice{
   224  				Group:      opt.MakeColSet(ord[i].ID()),
   225  				Descending: ord[i].Descending(),
   226  			})
   227  		}
   228  	}
   229  }
   230  
   231  // ToOrdering returns an opt.Ordering instance composed of the shortest possible
   232  // orderings that this instance allows. If there are several, then one is chosen
   233  // arbitrarily.
   234  func (oc *OrderingChoice) ToOrdering() opt.Ordering {
   235  	ordering := make(opt.Ordering, len(oc.Columns))
   236  	for i := range oc.Columns {
   237  		col := &oc.Columns[i]
   238  		ordering[i] = opt.MakeOrderingColumn(col.AnyID(), col.Descending)
   239  	}
   240  	return ordering
   241  }
   242  
   243  // ColSet returns the set of all non-optional columns that are part of this
   244  // instance. For example, (1,2,3) will be returned if the OrderingChoice is:
   245  //
   246  //   +1,(2|3) opt(4,5)
   247  //
   248  func (oc *OrderingChoice) ColSet() opt.ColSet {
   249  	var cs opt.ColSet
   250  	for i := range oc.Columns {
   251  		cs.UnionWith(oc.Columns[i].Group)
   252  	}
   253  	return cs
   254  }
   255  
   256  // Implies returns true if any ordering allowed by <oc> is also allowed by <other>.
   257  //
   258  // In the case of no optional or equivalent columns, Implies returns true when
   259  // the given ordering is a prefix of this ordering.
   260  //
   261  // Examples:
   262  //
   263  //   <empty>           implies <empty>
   264  //   +1                implies <empty>        (given set is prefix)
   265  //   +1                implies +1
   266  //   +1,-2             implies +1             (given set is prefix)
   267  //   +1,-2             implies +1,-2
   268  //   +1                implies +1 opt(2)      (unused optional col is ignored)
   269  //   -2,+1             implies +1 opt(2)      (optional col is ignored)
   270  //   +1                implies +(1|2)         (subset of choice)
   271  //   +(1|2)            implies +(1|2|3)       (subset of choice)
   272  //   +(1|2),-4         implies +(1|2|3),-(4|5)
   273  //   +(1|2) opt(4)     implies +(1|2|3) opt(4)
   274  //
   275  //   <empty>           !implies +1
   276  //   +1                !implies -1            (direction mismatch)
   277  //   +1                !implies +1,-2         (prefix matching not commutative)
   278  //   +1 opt(2)         !implies +1            (extra optional cols not allowed)
   279  //   +1 opt(2)         !implies +1 opt(3)
   280  //   +(1|2)            !implies -(1|2)        (direction mismatch)
   281  //   +(1|2)            !implies +(3|4)        (no intersection)
   282  //   +(1|2)            !implies +(2|3)        (intersects, but not subset)
   283  //   +(1|2|3)          !implies +(1|2)        (subset of choice not commutative)
   284  //   +(1|2)            !implies +1 opt(2)
   285  //
   286  func (oc *OrderingChoice) Implies(other *OrderingChoice) bool {
   287  	if !oc.Optional.SubsetOf(other.Optional) {
   288  		return false
   289  	}
   290  
   291  	for left, right := 0, 0; right < len(other.Columns); {
   292  		if left >= len(oc.Columns) {
   293  			return false
   294  		}
   295  
   296  		leftCol, rightCol := &oc.Columns[left], &other.Columns[right]
   297  
   298  		switch {
   299  		case leftCol.Descending == rightCol.Descending && leftCol.Group.SubsetOf(rightCol.Group):
   300  			// The columns match.
   301  			left, right = left+1, right+1
   302  
   303  		case leftCol.Group.Intersects(other.Optional):
   304  			// Left column is optional in the right set.
   305  			left++
   306  
   307  		default:
   308  			return false
   309  		}
   310  	}
   311  	return true
   312  }
   313  
   314  // Intersects returns true if there are orderings that satisfy both
   315  // OrderingChoices. See Intersection for more information.
   316  func (oc *OrderingChoice) Intersects(other *OrderingChoice) bool {
   317  	for left, right := 0, 0; left < len(oc.Columns) && right < len(other.Columns); {
   318  		leftCol, rightCol := &oc.Columns[left], &other.Columns[right]
   319  		switch {
   320  		case leftCol.Descending == rightCol.Descending && leftCol.Group.Intersects(rightCol.Group):
   321  			// The columns match.
   322  			left, right = left+1, right+1
   323  
   324  		case leftCol.Group.Intersects(other.Optional):
   325  			// Left column is optional in the right set.
   326  			left++
   327  
   328  		case rightCol.Group.Intersects(oc.Optional):
   329  			// Right column is optional in the left set.
   330  			right++
   331  
   332  		default:
   333  			return false
   334  		}
   335  	}
   336  	return true
   337  }
   338  
   339  // Intersection returns an OrderingChoice that Implies both ordering choices.
   340  // Can only be called if Intersects is true. Some examples:
   341  //
   342  //  +1           ∩ <empty> = +1
   343  //  +1           ∩ +1,+2   = +1,+2
   344  //  +1,+2 opt(3) ∩ +1,+3   = +1,+3,+2
   345  //
   346  // In general, OrderingChoice is not expressive enough to represent the
   347  // intersection. In such cases, an OrderingChoice representing a subset of the
   348  // intersection is returned. For example,
   349  //  +1 opt(2) ∩ +2 opt(1)
   350  // can be either +1,+2 or +2,+1; only one of these is returned. Note that
   351  // the function may not be commutative in this case. In practice, such cases are
   352  // unlikely.
   353  //
   354  // It is guaranteed that if one OrderingChoice Implies the other, it will also
   355  // be the Intersection.
   356  func (oc *OrderingChoice) Intersection(other *OrderingChoice) OrderingChoice {
   357  	// We have to handle Any cases separately because an Any ordering choice has
   358  	// no optional columns (even though semantically it should have all possible
   359  	// columns as optional).
   360  	if oc.Any() {
   361  		return other.Copy()
   362  	}
   363  	if other.Any() {
   364  		return oc.Copy()
   365  	}
   366  
   367  	result := make([]OrderingColumnChoice, 0, len(oc.Columns)+len(other.Columns))
   368  
   369  	left, right := 0, 0
   370  	for left < len(oc.Columns) && right < len(other.Columns) {
   371  		leftCol, rightCol := &oc.Columns[left], &other.Columns[right]
   372  
   373  		switch {
   374  		case leftCol.Descending == rightCol.Descending && leftCol.Group.Intersects(rightCol.Group):
   375  			// The columns match.
   376  			result = append(result, OrderingColumnChoice{
   377  				Group:      leftCol.Group.Intersection(rightCol.Group),
   378  				Descending: leftCol.Descending,
   379  			})
   380  			left, right = left+1, right+1
   381  
   382  		case leftCol.Group.Intersects(other.Optional):
   383  			// Left column is optional in the right set.
   384  			result = append(result, OrderingColumnChoice{
   385  				Group:      leftCol.Group.Intersection(other.Optional),
   386  				Descending: leftCol.Descending,
   387  			})
   388  			left++
   389  
   390  		case rightCol.Group.Intersects(oc.Optional):
   391  			// Right column is optional in the left set.
   392  			result = append(result, OrderingColumnChoice{
   393  				Group:      rightCol.Group.Intersection(oc.Optional),
   394  				Descending: rightCol.Descending,
   395  			})
   396  			right++
   397  
   398  		default:
   399  			panic(errors.AssertionFailedf("non-intersecting sets"))
   400  		}
   401  	}
   402  	// An ordering matched a prefix of the other. Append the tail of the other
   403  	// ordering.
   404  	for ; left < len(oc.Columns); left++ {
   405  		result = append(result, oc.Columns[left])
   406  	}
   407  	for ; right < len(other.Columns); right++ {
   408  		result = append(result, other.Columns[right])
   409  	}
   410  	return OrderingChoice{
   411  		Optional: oc.Optional.Intersection(other.Optional),
   412  		Columns:  result,
   413  	}
   414  }
   415  
   416  // SubsetOfCols is true if the OrderingChoice only references columns in the
   417  // given set.
   418  func (oc *OrderingChoice) SubsetOfCols(cs opt.ColSet) bool {
   419  	if !oc.Optional.SubsetOf(cs) {
   420  		return false
   421  	}
   422  	for i := range oc.Columns {
   423  		if !oc.Columns[i].Group.SubsetOf(cs) {
   424  			return false
   425  		}
   426  	}
   427  	return true
   428  }
   429  
   430  // CanProjectCols is true if at least one column in each ordering column group is
   431  // part of the given column set. For example, if the OrderingChoice is:
   432  //
   433  //   +1,-(2|3) opt(4,5)
   434  //
   435  // then CanProjectCols will behave as follows for these input sets:
   436  //
   437  //   (1,2)   => true
   438  //   (1,3)   => true
   439  //   (1,2,4) => true
   440  //   (1)     => false
   441  //   (3,4)   => false
   442  //
   443  func (oc *OrderingChoice) CanProjectCols(cs opt.ColSet) bool {
   444  	for i := range oc.Columns {
   445  		if !oc.Columns[i].Group.Intersects(cs) {
   446  			return false
   447  		}
   448  	}
   449  	return true
   450  }
   451  
   452  // MatchesAt returns true if the ordering column at the given index in this
   453  // instance matches the given column. The column matches if its id is part of
   454  // the equivalence group and if it has the same direction.
   455  func (oc *OrderingChoice) MatchesAt(index int, col opt.OrderingColumn) bool {
   456  	if oc.Optional.Contains(col.ID()) {
   457  		return true
   458  	}
   459  	choice := &oc.Columns[index]
   460  	if choice.Descending != col.Descending() {
   461  		return false
   462  	}
   463  	if !choice.Group.Contains(col.ID()) {
   464  		return false
   465  	}
   466  	return true
   467  }
   468  
   469  // AppendCol adds a new column to the end of the sequence of ordering columns
   470  // maintained by this instance. The new column has the given ID and direction as
   471  // the only ordering choice.
   472  func (oc *OrderingChoice) AppendCol(id opt.ColumnID, descending bool) {
   473  	ordCol := OrderingColumnChoice{Descending: descending}
   474  	ordCol.Group.Add(id)
   475  	oc.Optional.Remove(id)
   476  	oc.Columns = append(oc.Columns, ordCol)
   477  }
   478  
   479  // Copy returns a complete copy of this instance, with a private version of the
   480  // ordering column array.
   481  func (oc *OrderingChoice) Copy() OrderingChoice {
   482  	var other OrderingChoice
   483  	other.Optional = oc.Optional
   484  	other.Columns = make([]OrderingColumnChoice, len(oc.Columns))
   485  	copy(other.Columns, oc.Columns)
   486  	return other
   487  }
   488  
   489  // CanSimplify returns true if a call to Simplify would result in any changes to
   490  // the OrderingChoice. Changes include additional constant columns, removed
   491  // groups, and additional equivalent columns. This is used to quickly check
   492  // whether Simplify needs to be called without requiring allocations in the
   493  // common case. This logic should be changed in concert with the Simplify logic.
   494  func (oc *OrderingChoice) CanSimplify(fdset *props.FuncDepSet) bool {
   495  	if oc.Any() {
   496  		// Any ordering allowed, so can't simplify further.
   497  		return false
   498  	}
   499  
   500  	// Check whether optional columns can be added by the FD set.
   501  	optional := fdset.ComputeClosure(oc.Optional)
   502  	if !optional.Equals(oc.Optional) {
   503  		return true
   504  	}
   505  
   506  	closure := optional
   507  	for i := range oc.Columns {
   508  		group := &oc.Columns[i]
   509  
   510  		// If group contains an optional column, then group can be simplified
   511  		// or removed entirely.
   512  		if group.Group.Intersects(optional) {
   513  			return true
   514  		}
   515  
   516  		// If group is functionally determined by previous groups, then it can
   517  		// be removed entirely.
   518  		if group.Group.SubsetOf(closure) {
   519  			return true
   520  		}
   521  
   522  		// Check whether new equivalent columns can be added by the FD set.
   523  		equiv := fdset.ComputeEquivClosure(group.Group)
   524  		if !equiv.Equals(group.Group) {
   525  			return true
   526  		}
   527  
   528  		// Add this group's columns and find closure with new columns.
   529  		closure.UnionWith(equiv)
   530  		closure = fdset.ComputeClosure(closure)
   531  	}
   532  
   533  	return false
   534  }
   535  
   536  // Simplify uses the given FD set to streamline the orderings allowed by this
   537  // instance, and to potentially increase the number of allowed orderings:
   538  //
   539  //   1. Constant columns add additional optional column choices.
   540  //
   541  //   2. Equivalent columns allow additional choices within an ordering column
   542  //      group.
   543  //
   544  //   3. If the columns in a group are functionally determined by columns from
   545  //      previous groups, the group can be dropped. This technique is described
   546  //      in the "Reduce Order" section of this paper:
   547  //
   548  //        Simmen, David & Shekita, Eugene & Malkemus, Timothy. (1996).
   549  //        Fundamental Techniques for Order Optimization.
   550  //        Sigmod Record. Volume 25 Issue 2, June 1996. Pages 57-67.
   551  //        https://cs.uwaterloo.ca/~gweddell/cs798/p57-simmen.pdf
   552  //
   553  // This logic should be changed in concert with the CanSimplify logic.
   554  func (oc *OrderingChoice) Simplify(fdset *props.FuncDepSet) {
   555  	oc.Optional = fdset.ComputeClosure(oc.Optional)
   556  
   557  	closure := oc.Optional
   558  	n := 0
   559  	for i := range oc.Columns {
   560  		group := &oc.Columns[i]
   561  
   562  		// Constant columns from the FD set become optional ordering columns and
   563  		// so can be removed.
   564  		if group.Group.Intersects(oc.Optional) {
   565  			if group.Group.SubsetOf(oc.Optional) {
   566  				continue
   567  			}
   568  			group.Group = group.Group.Difference(oc.Optional)
   569  		}
   570  
   571  		// If this group is functionally determined from previous groups, then
   572  		// discard it.
   573  		if group.Group.SubsetOf(closure) {
   574  			continue
   575  		}
   576  
   577  		// Expand group with equivalent columns from FD set.
   578  		group.Group = fdset.ComputeEquivClosure(group.Group)
   579  
   580  		// Add this group's columns and find closure with the new columns.
   581  		closure = closure.Union(group.Group)
   582  		closure = fdset.ComputeClosure(closure)
   583  
   584  		if n != i {
   585  			oc.Columns[n] = oc.Columns[i]
   586  		}
   587  		n++
   588  	}
   589  	oc.Columns = oc.Columns[:n]
   590  
   591  	if len(oc.Columns) == 0 {
   592  		// Normalize Any case by dropping any optional columns.
   593  		oc.Optional = opt.ColSet{}
   594  	}
   595  }
   596  
   597  // Truncate removes all ordering columns beyond the given index. For example,
   598  // +1,+(2|3),-4 opt(5,6) would be truncated to:
   599  //
   600  //   prefix=0  => opt(5,6)
   601  //   prefix=1  => +1 opt(5,6)
   602  //   prefix=2  => +1,+(2|3) opt(5,6)
   603  //   prefix=3+ => +1,+(2|3),-4 opt(5,6)
   604  //
   605  func (oc *OrderingChoice) Truncate(prefix int) {
   606  	if prefix < len(oc.Columns) {
   607  		oc.Columns = oc.Columns[:prefix]
   608  		if len(oc.Columns) == 0 {
   609  			// Normalize Any case by dropping any optional columns.
   610  			oc.Optional = opt.ColSet{}
   611  		}
   612  	}
   613  }
   614  
   615  // ProjectCols removes any references to columns that are not in the given
   616  // set. This method can only be used when the OrderingChoice can be expressed
   617  // with the given columns; i.e. all groups have at least one column in the set.
   618  func (oc *OrderingChoice) ProjectCols(cols opt.ColSet) {
   619  	if !oc.Optional.SubsetOf(cols) {
   620  		oc.Optional = oc.Optional.Intersection(cols)
   621  	}
   622  	for i := range oc.Columns {
   623  		if !oc.Columns[i].Group.SubsetOf(cols) {
   624  			oc.Columns[i].Group = oc.Columns[i].Group.Intersection(cols)
   625  			if oc.Columns[i].Group.Empty() {
   626  				panic(errors.AssertionFailedf("no columns left from group"))
   627  			}
   628  		}
   629  	}
   630  }
   631  
   632  // PrefixIntersection computes an OrderingChoice which:
   633  //  - implies <oc> (this instance), and
   634  //  - implies a "segmented ordering", which is any ordering which starts with a
   635  //    permutation of all columns in <prefix> followed by the <suffix> ordering.
   636  //
   637  // Note that <prefix> and <suffix> cannot have any columns in common.
   638  //
   639  // Such an ordering can be computed via the following rules:
   640  //
   641  //  - if <prefix> and <suffix> are empty: return this instance.
   642  //
   643  //  - if <oc> is empty: generate an arbitrary segmented ordering.
   644  //
   645  //  - if the first column of <oc> is either in <prefix> or is the first column
   646  //    of <suffix> while <prefix> is empty: this column is the first column of
   647  //    the result; calculate the rest recursively.
   648  //
   649  func (oc OrderingChoice) PrefixIntersection(
   650  	prefix opt.ColSet, suffix []OrderingColumnChoice,
   651  ) (_ OrderingChoice, ok bool) {
   652  	var result OrderingChoice
   653  	oc = oc.Copy()
   654  
   655  	prefix = prefix.Copy()
   656  
   657  	for {
   658  		switch {
   659  		case prefix.Empty() && len(suffix) == 0:
   660  			// Any ordering is allowed by <prefix>+<suffix>, so use <oc> directly.
   661  			result.Columns = append(result.Columns, oc.Columns...)
   662  			return result, true
   663  		case len(oc.Columns) == 0:
   664  			// Any ordering is allowed by <oc>, so pick an arbitrary ordering of the
   665  			// columns in <prefix> then append suffix.
   666  			// TODO(justin): investigate picking an order more intelligently here.
   667  			for col, ok := prefix.Next(0); ok; col, ok = prefix.Next(col + 1) {
   668  				result.AppendCol(col, false /* descending */)
   669  			}
   670  
   671  			result.Columns = append(result.Columns, suffix...)
   672  			return result, true
   673  		case prefix.Empty() && len(oc.Columns) > 0 && len(suffix) > 0 &&
   674  			oc.Columns[0].Group.Intersects(suffix[0].Group) &&
   675  			oc.Columns[0].Descending == suffix[0].Descending:
   676  			// <prefix> is empty, and <suffix> and <oc> agree on the first column, so
   677  			// emit that column, remove it from both, and loop.
   678  			newCol := oc.Columns[0]
   679  			newCol.Group = oc.Columns[0].Group.Intersection(suffix[0].Group)
   680  			result.Columns = append(result.Columns, newCol)
   681  
   682  			oc.Columns = oc.Columns[1:]
   683  			suffix = suffix[1:]
   684  		case len(oc.Columns) > 0 && prefix.Intersects(oc.Columns[0].Group):
   685  			// <prefix> contains the first column in <oc>, so emit it and remove it
   686  			// from both.
   687  			result.Columns = append(result.Columns, oc.Columns[0])
   688  
   689  			prefix.DifferenceWith(oc.Columns[0].Group)
   690  			oc.Columns = oc.Columns[1:]
   691  		default:
   692  			// If no rule applied, fail.
   693  			return OrderingChoice{}, false
   694  		}
   695  	}
   696  }
   697  
   698  // Equals returns true if the set of orderings matched by this instance is the
   699  // same as the set matched by the given instance.
   700  func (oc *OrderingChoice) Equals(rhs *OrderingChoice) bool {
   701  	if len(oc.Columns) != len(rhs.Columns) {
   702  		return false
   703  	}
   704  	if !oc.Optional.Equals(rhs.Optional) {
   705  		return false
   706  	}
   707  
   708  	for i := range oc.Columns {
   709  		left := &oc.Columns[i]
   710  		y := &rhs.Columns[i]
   711  
   712  		if left.Descending != y.Descending {
   713  			return false
   714  		}
   715  		if !left.Group.Equals(y.Group) {
   716  			return false
   717  		}
   718  	}
   719  	return true
   720  }
   721  
   722  func (oc OrderingChoice) String() string {
   723  	var buf bytes.Buffer
   724  	oc.Format(&buf)
   725  	return buf.String()
   726  }
   727  
   728  // Format writes the OrderingChoice to the given buffer in a human-readable
   729  // string representation that can also be parsed by ParseOrderingChoice:
   730  //
   731  //   +1
   732  //   +1,-2
   733  //   +(1|2)
   734  //   +(1|2),+3
   735  //   -(3|4),+5 opt(1,2)
   736  //
   737  func (oc OrderingChoice) Format(buf *bytes.Buffer) {
   738  	for g := range oc.Columns {
   739  		group := &oc.Columns[g]
   740  		count := group.Group.Len()
   741  
   742  		if group.Descending {
   743  			buf.WriteByte('-')
   744  		} else {
   745  			buf.WriteByte('+')
   746  		}
   747  
   748  		// Write equivalence group.
   749  		if count > 1 {
   750  			buf.WriteByte('(')
   751  		}
   752  		first := true
   753  		for i, ok := group.Group.Next(0); ok; i, ok = group.Group.Next(i + 1) {
   754  			if !first {
   755  				buf.WriteByte('|')
   756  			} else {
   757  				first = false
   758  			}
   759  			fmt.Fprintf(buf, "%d", i)
   760  		}
   761  		if count > 1 {
   762  			buf.WriteByte(')')
   763  		}
   764  
   765  		if g+1 != len(oc.Columns) {
   766  			buf.WriteByte(',')
   767  		}
   768  	}
   769  
   770  	// Write set of optional columns.
   771  	if !oc.Optional.Empty() {
   772  		if len(oc.Columns) != 0 {
   773  			buf.WriteByte(' ')
   774  		}
   775  		fmt.Fprintf(buf, "opt%s", oc.Optional)
   776  	}
   777  }
   778  
   779  // AnyID returns the ID of an arbitrary member of the group of equivalent
   780  // columns.
   781  func (oc *OrderingColumnChoice) AnyID() opt.ColumnID {
   782  	id, ok := oc.Group.Next(0)
   783  	if !ok {
   784  		panic(errors.AssertionFailedf("column choice group should have at least one column id"))
   785  	}
   786  	return id
   787  }