github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/opt/constraint/key.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 constraint
    12  
    13  import (
    14  	"bytes"
    15  	"fmt"
    16  
    17  	"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
    18  )
    19  
    20  // EmptyKey has zero values. If it's a start key, then it sorts before all
    21  // other keys. If it's an end key, then it sorts after all other keys.
    22  var EmptyKey = Key{}
    23  
    24  // Key is a composite of N typed datum values that are ordered from most
    25  // significant to least significant for purposes of sorting. The datum values
    26  // correspond to a set of columns; it is the responsibility of the calling code
    27  // to keep track of them.
    28  // Key is immutable; it cannot be changed once created.
    29  type Key struct {
    30  	// firstVal stores the first value in the key. Subsequent values are stored
    31  	// in otherVals. Inlining the first value avoids an extra allocation in the
    32  	// common case of a single value in the key.
    33  	firstVal tree.Datum
    34  
    35  	// otherVals is an ordered list of typed datum values. It only stores values
    36  	// after the first, and is nil if there is <= 1 value.
    37  	otherVals tree.Datums
    38  }
    39  
    40  // MakeKey constructs a simple one dimensional key having the given value. If
    41  // val is nil, then MakeKey returns an empty key.
    42  func MakeKey(val tree.Datum) Key {
    43  	return Key{firstVal: val}
    44  }
    45  
    46  // MakeCompositeKey constructs an N-dimensional key from the given slice of
    47  // values.
    48  func MakeCompositeKey(vals ...tree.Datum) Key {
    49  	switch len(vals) {
    50  	case 0:
    51  		return Key{}
    52  	case 1:
    53  		return Key{firstVal: vals[0]}
    54  	}
    55  	return Key{firstVal: vals[0], otherVals: vals[1:]}
    56  }
    57  
    58  // IsEmpty is true if this key has zero values.
    59  func (k Key) IsEmpty() bool {
    60  	return k.firstVal == nil
    61  }
    62  
    63  // IsNull is true if this key is the NULL value.
    64  func (k Key) IsNull() bool {
    65  	return k.Length() == 1 && k.firstVal == tree.DNull
    66  }
    67  
    68  // Length returns the number of values in the key. If the count is zero, then
    69  // this is an empty key.
    70  func (k Key) Length() int {
    71  	if k.IsEmpty() {
    72  		return 0
    73  	}
    74  	return 1 + len(k.otherVals)
    75  }
    76  
    77  // Value returns the nth value of the key. If the index is out-of-range, then
    78  // Value will panic.
    79  func (k Key) Value(nth int) tree.Datum {
    80  	if k.firstVal != nil && nth == 0 {
    81  		return k.firstVal
    82  	}
    83  	return k.otherVals[nth-1]
    84  }
    85  
    86  // Compare returns an integer indicating the ordering of the two keys. The
    87  // result will be 0 if the keys are equal, -1 if this key is less than the
    88  // given key, or 1 if this key is greater.
    89  //
    90  // Comparisons between keys where one key is a prefix of the other have special
    91  // handling which can be controlled via the key extension parameters. Key
    92  // extensions specify whether each key is conceptually suffixed with negative
    93  // or positive infinity for purposes of comparison. For example, if k is /1/2,
    94  // then:
    95  //   k (kExt = ExtendLow) : /1/2/Low
    96  //   k (kExt = ExtendHigh): /1/2/High
    97  //
    98  // These extensions have no effect if one key is not a prefix of the other,
    99  // since the comparison would already have concluded in previous values. But
   100  // if comparison proceeds all the way to the end of one of the keys, then the
   101  // extension determines which key is greater. This enables correct comparison
   102  // of start and end keys in spans which may be either inclusive or exclusive.
   103  // Here is the mapping:
   104  //   [/1/2 - ...] (inclusive start key): ExtendLow : /1/2/Low
   105  //   (/1/2 - ...] (exclusive start key): ExtendHigh: /1/2/High
   106  //   [... - /1/2] (inclusive end key)  : ExtendHigh: /1/2/High
   107  //   [... - /1/2) (exclusive end key)  : ExtendLow : /1/2/Low
   108  func (k Key) Compare(keyCtx *KeyContext, l Key, kext, lext KeyExtension) int {
   109  	klen := k.Length()
   110  	llen := l.Length()
   111  	for i := 0; i < klen && i < llen; i++ {
   112  		if cmp := keyCtx.Compare(i, k.Value(i), l.Value(i)); cmp != 0 {
   113  			return cmp
   114  		}
   115  	}
   116  
   117  	if klen < llen {
   118  		// k matches a prefix of l:
   119  		//   k = /1
   120  		//   l = /1/2
   121  		// Which of these is "smaller" depends on whether k is extended with
   122  		// -inf or with +inf:
   123  		//   k (ExtendLow)  = /1/Low  < /1/2  ->  k is smaller (-1)
   124  		//   k (ExtendHigh) = /1/High > /1/2  ->  k is bigger  (1)
   125  		return kext.ToCmp()
   126  	} else if klen > llen {
   127  		// Inverse case of above.
   128  		return -lext.ToCmp()
   129  	}
   130  
   131  	// Equal keys:
   132  	//   k (ExtendLow)  vs. l (ExtendLow)   ->  equal   (0)
   133  	//   k (ExtendLow)  vs. l (ExtendHigh)  ->  smaller (-1)
   134  	//   k (ExtendHigh) vs. l (ExtendLow)   ->  bigger  (1)
   135  	//   k (ExtendHigh) vs. l (ExtendHigh)  ->  equal   (0)
   136  	if kext == lext {
   137  		return 0
   138  	}
   139  	return kext.ToCmp()
   140  }
   141  
   142  // Concat creates a new composite key by extending this key's values with the
   143  // values of the given key. The new key's length is len(k) + len(l).
   144  func (k Key) Concat(l Key) Key {
   145  	klen := k.Length()
   146  	llen := l.Length()
   147  
   148  	if klen == 0 {
   149  		return l
   150  	}
   151  	if llen == 0 {
   152  		return k
   153  	}
   154  
   155  	vals := make(tree.Datums, klen+llen-1)
   156  	copy(vals, k.otherVals)
   157  	vals[klen-1] = l.firstVal
   158  	copy(vals[klen:], l.otherVals)
   159  	return Key{firstVal: k.firstVal, otherVals: vals}
   160  }
   161  
   162  // CutFront returns the key with the first numCols values removed.
   163  // Example:
   164  //   [/1/2 - /1/3].CutFront(1) = [/2 - /3]
   165  func (k Key) CutFront(numCols int) Key {
   166  	if numCols == 0 {
   167  		return k
   168  	}
   169  	if len(k.otherVals) < numCols {
   170  		return EmptyKey
   171  	}
   172  	return Key{
   173  		firstVal:  k.otherVals[numCols-1],
   174  		otherVals: k.otherVals[numCols:],
   175  	}
   176  }
   177  
   178  // IsNextKey returns true if:
   179  //  - k and other have the same length;
   180  //  - on all but the last column, k and other have the same values;
   181  //  - on the last column, k has the datum that follows other's datum (for
   182  //    types that support it).
   183  // For example: /2.IsNextKey(/1) is true.
   184  func (k Key) IsNextKey(keyCtx *KeyContext, other Key) bool {
   185  	n := k.Length()
   186  	if n != other.Length() {
   187  		return false
   188  	}
   189  	// All the datums up to the last one must be equal.
   190  	for i := 0; i < n-1; i++ {
   191  		if keyCtx.Compare(i, k.Value(i), other.Value(i)) != 0 {
   192  			return false
   193  		}
   194  	}
   195  
   196  	next, ok := keyCtx.Next(n-1, other.Value(n-1))
   197  	return ok && keyCtx.Compare(n-1, k.Value(n-1), next) == 0
   198  }
   199  
   200  // Next returns the next key; this only works for discrete types like integers.
   201  // It is guaranteed that there are no  possible keys in the span
   202  //   ( key, Next(keu) ).
   203  //
   204  // Examples:
   205  //   Next(/1/2) = /1/3
   206  //   Next(/1/false) = /1/true
   207  //   Next(/1/true) returns !ok
   208  //   Next(/'foo') = /'foo\x00'
   209  //
   210  // If a column is descending, the values on that column go backwards:
   211  //   Next(/2) = /1
   212  //
   213  // The key cannot be empty.
   214  func (k Key) Next(keyCtx *KeyContext) (_ Key, ok bool) {
   215  	// TODO(radu): here we could do a better job: if we know the last value is the
   216  	// maximum possible value, we could shorten the key; for example
   217  	//   Next(/1/true) -> /2
   218  	// This is a bit tricky to implement because of NULL values (e.g. on a
   219  	// descending nullable column, "false" is not the minimum value, NULL is).
   220  	col := k.Length() - 1
   221  	nextVal, ok := keyCtx.Next(col, k.Value(col))
   222  	if !ok {
   223  		return Key{}, false
   224  	}
   225  	if col == 0 {
   226  		return Key{firstVal: nextVal}, true
   227  	}
   228  	// Keep the key up to col, and replace the value for col with nextVal.
   229  	vals := make([]tree.Datum, col)
   230  	copy(vals[:col-1], k.otherVals)
   231  	vals[col-1] = nextVal
   232  	return Key{firstVal: k.firstVal, otherVals: vals}, true
   233  }
   234  
   235  // Prev returns the next key; this only works for discrete types like integers.
   236  //
   237  // Examples:
   238  //   Prev(/1/2) = /1/1
   239  //   Prev(/1/true) = /1/false
   240  //   Prev(/1/false) returns !ok.
   241  //   Prev(/'foo') returns !ok.
   242  //
   243  // If a column is descending, the values on that column go backwards:
   244  //   Prev(/1) = /2
   245  //
   246  // If this is the minimum possible key, returns EmptyKey.
   247  func (k Key) Prev(keyCtx *KeyContext) (_ Key, ok bool) {
   248  	col := k.Length() - 1
   249  	prevVal, ok := keyCtx.Prev(col, k.Value(col))
   250  	if !ok {
   251  		return Key{}, false
   252  	}
   253  	if col == 0 {
   254  		return Key{firstVal: prevVal}, true
   255  	}
   256  	// Keep the key up to col, and replace the value for col with prevVal.
   257  	vals := make([]tree.Datum, col)
   258  	copy(vals[:col-1], k.otherVals)
   259  	vals[col-1] = prevVal
   260  	return Key{firstVal: k.firstVal, otherVals: vals}, true
   261  }
   262  
   263  // String formats a key like this:
   264  //  EmptyKey         : empty string
   265  //  Key with 1 value : /2
   266  //  Key with 2 values: /5/1
   267  //  Key with 3 values: /3/6/4
   268  func (k Key) String() string {
   269  	var buf bytes.Buffer
   270  	for i := 0; i < k.Length(); i++ {
   271  		fmt.Fprintf(&buf, "/%s", k.Value(i))
   272  	}
   273  	return buf.String()
   274  }
   275  
   276  // KeyContext contains the necessary metadata for comparing Keys.
   277  type KeyContext struct {
   278  	Columns Columns
   279  	EvalCtx *tree.EvalContext
   280  }
   281  
   282  // MakeKeyContext initializes a KeyContext.
   283  func MakeKeyContext(cols *Columns, evalCtx *tree.EvalContext) KeyContext {
   284  	return KeyContext{Columns: *cols, EvalCtx: evalCtx}
   285  }
   286  
   287  // Compare two values for a given column.
   288  // Returns 0 if the values are equal, -1 if a is less than b, or 1 if b is less
   289  // than a.
   290  func (c *KeyContext) Compare(colIdx int, a, b tree.Datum) int {
   291  	// Fast path when the datums are the same.
   292  	if a == b {
   293  		return 0
   294  	}
   295  	cmp := a.Compare(c.EvalCtx, b)
   296  	if c.Columns.Get(colIdx).Descending() {
   297  		cmp = -cmp
   298  	}
   299  	return cmp
   300  }
   301  
   302  // Next returns the next value on a given column (for discrete types like
   303  // integers). See Datum.Next/Prev.
   304  func (c *KeyContext) Next(colIdx int, val tree.Datum) (_ tree.Datum, ok bool) {
   305  	if c.Columns.Get(colIdx).Ascending() {
   306  		if val.IsMax(c.EvalCtx) {
   307  			return nil, false
   308  		}
   309  		return val.Next(c.EvalCtx)
   310  	}
   311  	if val.IsMin(c.EvalCtx) {
   312  		return nil, false
   313  	}
   314  	return val.Prev(c.EvalCtx)
   315  }
   316  
   317  // Prev returns the previous value on a given column (for discrete types like
   318  // integers). See Datum.Next/Prev.
   319  func (c *KeyContext) Prev(colIdx int, val tree.Datum) (_ tree.Datum, ok bool) {
   320  	if c.Columns.Get(colIdx).Ascending() {
   321  		if val.IsMin(c.EvalCtx) {
   322  			return nil, false
   323  		}
   324  		return val.Prev(c.EvalCtx)
   325  	}
   326  	if val.IsMax(c.EvalCtx) {
   327  		return nil, false
   328  	}
   329  	return val.Next(c.EvalCtx)
   330  }