github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/opt/constraint/span.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 16 "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" 17 "github.com/cockroachdb/errors" 18 ) 19 20 // SpanBoundary specifies whether a span endpoint is inclusive or exclusive of 21 // its start or end key. An inclusive boundary is represented as '[' and an 22 // exclusive boundary is represented as ')'. Examples: 23 // [/0 - /1] (inclusive, inclusive) 24 // [/1 - /10) (inclusive, exclusive) 25 type SpanBoundary bool 26 27 const ( 28 // IncludeBoundary indicates that the boundary does include the respective 29 // key. 30 IncludeBoundary SpanBoundary = false 31 32 // ExcludeBoundary indicates that the boundary does not include the 33 // respective key. 34 ExcludeBoundary SpanBoundary = true 35 ) 36 37 // Span represents the range between two composite keys. The end keys of the 38 // range can be inclusive or exclusive. Each key value within the range is 39 // an N-tuple of datum values, one for each constrained column. Here are some 40 // examples: 41 // @1 < 100 : [ - /100) 42 // @1 >= 100 : [/100 - ] 43 // @1 >= 1 AND @1 <= 10 : [/1 - /10] 44 // (@1 = 100 AND @2 > 10) OR (@1 > 100 AND @1 <= 101): (/100/10 - /101] 45 type Span struct { 46 // Start is the starting boundary for the span. 47 start Key 48 49 // End is the ending boundary for the span. 50 end Key 51 52 // startBoundary indicates whether the span contains the start key value. 53 startBoundary SpanBoundary 54 55 // endBoundary indicates whether the span contains the the end key value. 56 endBoundary SpanBoundary 57 } 58 59 // UnconstrainedSpan is the span without any boundaries. 60 var UnconstrainedSpan = Span{} 61 62 // IsUnconstrained is true if the span does not constrain the key range. Both 63 // the start and end boundaries are empty. This is the default state of a Span 64 // before Set is called. Unconstrained spans cannot be used in constraints, 65 // since the absence of a constraint is equivalent to an unconstrained span. 66 func (sp *Span) IsUnconstrained() bool { 67 startUnconstrained := sp.start.IsEmpty() || (sp.start.IsNull() && sp.startBoundary == IncludeBoundary) 68 endUnconstrained := sp.end.IsEmpty() 69 70 return startUnconstrained && endUnconstrained 71 } 72 73 // HasSingleKey is true if the span contains exactly one key. This is true when 74 // the start key is the same as the end key, and both boundaries are inclusive. 75 func (sp *Span) HasSingleKey(evalCtx *tree.EvalContext) bool { 76 l := sp.start.Length() 77 if l == 0 || l != sp.end.Length() { 78 return false 79 } 80 if sp.startBoundary != IncludeBoundary || sp.endBoundary != IncludeBoundary { 81 return false 82 } 83 for i, n := 0, l; i < n; i++ { 84 if sp.start.Value(i).Compare(evalCtx, sp.end.Value(i)) != 0 { 85 return false 86 } 87 } 88 return true 89 } 90 91 // StartKey returns the start key. 92 func (sp *Span) StartKey() Key { 93 return sp.start 94 } 95 96 // StartBoundary returns whether the start key is included or excluded. 97 func (sp *Span) StartBoundary() SpanBoundary { 98 return sp.startBoundary 99 } 100 101 // EndKey returns the end key. 102 func (sp *Span) EndKey() Key { 103 return sp.end 104 } 105 106 // EndBoundary returns whether the end key is included or excluded. 107 func (sp *Span) EndBoundary() SpanBoundary { 108 return sp.endBoundary 109 } 110 111 // Init sets the boundaries of this span to the given values. The following 112 // spans are not allowed: 113 // 1. Empty span (should never be used in a constraint); not verified. 114 // 2. Exclusive empty key boundary (use inclusive instead); causes panic. 115 func (sp *Span) Init(start Key, startBoundary SpanBoundary, end Key, endBoundary SpanBoundary) { 116 if start.IsEmpty() && startBoundary == ExcludeBoundary { 117 // Enforce one representation for empty boundary. 118 panic(errors.AssertionFailedf("an empty start boundary must be inclusive")) 119 } 120 if end.IsEmpty() && endBoundary == ExcludeBoundary { 121 // Enforce one representation for empty boundary. 122 panic(errors.AssertionFailedf("an empty end boundary must be inclusive")) 123 } 124 125 sp.start = start 126 sp.startBoundary = startBoundary 127 sp.end = end 128 sp.endBoundary = endBoundary 129 } 130 131 // Compare returns an integer indicating the ordering of the two spans. The 132 // result will be 0 if the spans are equal, -1 if this span is less than the 133 // given span, or 1 if this span is greater. Spans are first compared based on 134 // their start boundaries. If those are equal, then their end boundaries are 135 // compared. An inclusive start boundary is less than an exclusive start 136 // boundary, and an exclusive end boundary is less than an inclusive end 137 // boundary. Here are examples of how various spans are ordered, with 138 // equivalent extended keys shown as well (see Key.Compare comment): 139 // [ - /2 ) = /Low - /2/Low 140 // [ - /2/1) = /Low - /2/1/Low 141 // [ - /2/1] = /Low - /2/1/High 142 // [ - /2 ] = /Low - /2/High 143 // [ - ] = /Low - /High 144 // [/1 - /2/1) = /1/Low - /2/1/Low 145 // [/1 - /2/1] = /1/Low - /2/1/High 146 // [/1 - ] = /1/Low - /High 147 // [/1/1 - /2 ) = /1/1/Low - /2/Low 148 // [/1/1 - /2 ] = /1/1/Low - /2/High 149 // [/1/1 - ] = /1/1/Low - /High 150 // (/1/1 - /2 ) = /1/1/High - /2/Low 151 // (/1/1 - /2 ] = /1/1/High - /2/High 152 // (/1/1 - ] = /1/1/High - /High 153 // (/1 - /2/1) = /1/High - /2/1/Low 154 // (/1 - /2/1] = /1/High - /2/1/High 155 // (/1 - ] = /1/High - /High 156 func (sp *Span) Compare(keyCtx *KeyContext, other *Span) int { 157 // Span with lowest start boundary is less than the other. 158 if cmp := sp.CompareStarts(keyCtx, other); cmp != 0 { 159 return cmp 160 } 161 162 // Start boundary is same, so span with lowest end boundary is less than 163 // the other. 164 if cmp := sp.CompareEnds(keyCtx, other); cmp != 0 { 165 return cmp 166 } 167 168 // End boundary is same as well, so spans are the same. 169 return 0 170 } 171 172 // CompareStarts returns an integer indicating the ordering of the start 173 // boundaries of the two spans. The result will be 0 if the spans have the same 174 // start boundary, -1 if this span has a smaller start boundary than the given 175 // span, or 1 if this span has a bigger start boundary than the given span. 176 func (sp *Span) CompareStarts(keyCtx *KeyContext, other *Span) int { 177 return sp.start.Compare(keyCtx, other.start, sp.startExt(), other.startExt()) 178 } 179 180 // CompareEnds returns an integer indicating the ordering of the end boundaries 181 // of the two spans. The result will be 0 if the spans have the same end 182 // boundary, -1 if this span has a smaller end boundary than the given span, or 183 // 1 if this span has a bigger end boundary than the given span. 184 func (sp *Span) CompareEnds(keyCtx *KeyContext, other *Span) int { 185 return sp.end.Compare(keyCtx, other.end, sp.endExt(), other.endExt()) 186 } 187 188 // StartsAfter returns true if this span is greater than the given span and 189 // does not overlap it. In other words, this span's start boundary is greater 190 // or equal to the given span's end boundary. 191 func (sp *Span) StartsAfter(keyCtx *KeyContext, other *Span) bool { 192 return sp.start.Compare(keyCtx, other.end, sp.startExt(), other.endExt()) >= 0 193 } 194 195 // StartsStrictlyAfter returns true if this span is greater than the given span and 196 // does not overlap or touch it. In other words, this span's start boundary is 197 // strictly greater than the given span's end boundary. 198 func (sp *Span) StartsStrictlyAfter(keyCtx *KeyContext, other *Span) bool { 199 return sp.start.Compare(keyCtx, other.end, sp.startExt(), other.endExt()) > 0 200 } 201 202 // TryIntersectWith finds the overlap between this span and the given span. 203 // This span is updated to only cover the range that is common to both spans. 204 // If there is no overlap, then this span will not be updated, and 205 // TryIntersectWith will return false. 206 func (sp *Span) TryIntersectWith(keyCtx *KeyContext, other *Span) bool { 207 cmpStarts := sp.CompareStarts(keyCtx, other) 208 if cmpStarts > 0 { 209 // If this span's start boundary is >= the other span's end boundary, 210 // then intersection is empty. 211 if sp.start.Compare(keyCtx, other.end, sp.startExt(), other.endExt()) >= 0 { 212 return false 213 } 214 } 215 216 cmpEnds := sp.CompareEnds(keyCtx, other) 217 if cmpEnds < 0 { 218 // If this span's end boundary is <= the other span's start boundary, 219 // then intersection is empty. 220 if sp.end.Compare(keyCtx, other.start, sp.endExt(), other.startExt()) <= 0 { 221 return false 222 } 223 } 224 225 // Only update now that it's known that intersection is not empty. 226 if cmpStarts < 0 { 227 sp.start = other.start 228 sp.startBoundary = other.startBoundary 229 } 230 if cmpEnds > 0 { 231 sp.end = other.end 232 sp.endBoundary = other.endBoundary 233 } 234 return true 235 } 236 237 // TryUnionWith attempts to merge this span with the given span. If the merged 238 // spans cannot be expressed as a single span, then TryUnionWith will not 239 // update the span and TryUnionWith returns false. This could occur if the 240 // spans are disjoint, for example: 241 // [/1 - /5] UNION [/10 - /15] 242 // 243 // Otherwise, this span is updated to the merged span range and TryUnionWith 244 // returns true. If the resulting span does not constrain the range [ - ], then 245 // its IsUnconstrained method returns true, and it cannot be used as part of a 246 // constraint in a constraint set. 247 func (sp *Span) TryUnionWith(keyCtx *KeyContext, other *Span) bool { 248 // Determine the minimum start boundary. 249 cmpStartKeys := sp.CompareStarts(keyCtx, other) 250 251 var cmp int 252 if cmpStartKeys < 0 { 253 // This span is less, so see if there's any "space" after it and before 254 // the start of the other span. 255 cmp = sp.end.Compare(keyCtx, other.start, sp.endExt(), other.startExt()) 256 } else if cmpStartKeys > 0 { 257 // This span is greater, so see if there's any "space" before it and 258 // after the end of the other span. 259 cmp = other.end.Compare(keyCtx, sp.start, other.endExt(), sp.startExt()) 260 } 261 if cmp < 0 { 262 // There's "space" between spans, so union of these spans can't be 263 // expressed as a single span. 264 return false 265 } 266 267 // Determine the maximum end boundary. 268 cmpEndKeys := sp.CompareEnds(keyCtx, other) 269 270 // Create the merged span. 271 if cmpStartKeys > 0 { 272 sp.start = other.start 273 sp.startBoundary = other.startBoundary 274 } 275 if cmpEndKeys < 0 { 276 sp.end = other.end 277 sp.endBoundary = other.endBoundary 278 } 279 return true 280 } 281 282 // PreferInclusive tries to convert exclusive keys to inclusive keys. This is 283 // only possible if the relevant type supports Next/Prev. 284 // 285 // We prefer inclusive constraints because we can extend inclusive constraints 286 // with more constraints on columns that follow. 287 // 288 // Examples: 289 // - for an integer column (/1 - /5) => [/2 - /4]. 290 // - for a descending integer column (/5 - /1) => (/4 - /2). 291 // - for a string column, we don't have Prev so 292 // (/foo - /qux) => [/foo\x00 - /qux). 293 // - for a decimal column, we don't have either Next or Prev so we can't 294 // change anything. 295 func (sp *Span) PreferInclusive(keyCtx *KeyContext) { 296 if sp.startBoundary == ExcludeBoundary { 297 if key, ok := sp.start.Next(keyCtx); ok { 298 sp.start = key 299 sp.startBoundary = IncludeBoundary 300 } 301 } 302 if sp.endBoundary == ExcludeBoundary { 303 if key, ok := sp.end.Prev(keyCtx); ok { 304 sp.end = key 305 sp.endBoundary = IncludeBoundary 306 } 307 } 308 } 309 310 // CutFront removes the first numCols columns in both keys. 311 func (sp *Span) CutFront(numCols int) { 312 sp.start = sp.start.CutFront(numCols) 313 sp.end = sp.end.CutFront(numCols) 314 } 315 316 func (sp *Span) startExt() KeyExtension { 317 // Trivial cast of start boundary value: 318 // IncludeBoundary (false) = ExtendLow (false) 319 // ExcludeBoundary (true) = ExtendHigh (true) 320 return KeyExtension(sp.startBoundary) 321 } 322 323 func (sp *Span) endExt() KeyExtension { 324 // Invert end boundary value: 325 // IncludeBoundary (false) = ExtendHigh (true) 326 // ExcludeBoundary (true) = ExtendLow (false) 327 return KeyExtension(!sp.endBoundary) 328 } 329 330 // String formats a Span. Inclusivity/exclusivity is shown using 331 // brackets/parens. Some examples: 332 // [1 - 2] 333 // (1/1 - 2) 334 // [ - 5/6) 335 // [1 - ] 336 // [ - ] 337 func (sp Span) String() string { 338 var buf bytes.Buffer 339 if sp.startBoundary == IncludeBoundary { 340 buf.WriteRune('[') 341 } else { 342 buf.WriteRune('(') 343 } 344 345 buf.WriteString(sp.start.String()) 346 buf.WriteString(" - ") 347 buf.WriteString(sp.end.String()) 348 349 if sp.endBoundary == IncludeBoundary { 350 buf.WriteRune(']') 351 } else { 352 buf.WriteRune(')') 353 } 354 355 return buf.String() 356 }