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 }