github.com/dolthub/go-mysql-server@v0.18.0/sql/range_test.go (about) 1 // Copyright 2021 Dolthub, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package sql_test 16 17 import ( 18 "fmt" 19 "testing" 20 21 "github.com/shopspring/decimal" 22 "github.com/stretchr/testify/assert" 23 "github.com/stretchr/testify/require" 24 25 "github.com/dolthub/go-mysql-server/sql" 26 "github.com/dolthub/go-mysql-server/sql/expression" 27 "github.com/dolthub/go-mysql-server/sql/types" 28 ) 29 30 var rangeType = types.Uint8 31 32 func TestRangeOverlapTwoColumns(t *testing.T) { 33 ctx := sql.NewEmptyContext() 34 x, y, _, values2, _, _ := setup() 35 36 tests := []struct { 37 reference sql.Expression 38 ranges sql.RangeCollection 39 }{ 40 { 41 or( 42 and(lt(x, 2), gt(y, 5)), 43 and(gt(x, 8), gt(y, 5)), 44 and(gt(x, 5), gt(y, 8)), 45 ), 46 sql.RangeCollection{ 47 r(rlt(2), rgt(5)), 48 r(rgt(8), rgt(5)), 49 r(rgt(5), rgt(8)), 50 }, 51 }, 52 { 53 or( 54 and(lt(x, 2), gt(y, 5)), 55 and(gt(x, 8), gt(y, 5)), 56 and(gt(x, 5), lt(y, 8)), 57 ), 58 sql.RangeCollection{ 59 r(rlt(2), rgt(5)), 60 r(rgt(8), rgt(5)), 61 r(rgt(5), rlt(8)), 62 }, 63 }, 64 { 65 or( 66 and(gt(x, 1), gt(y, 1)), 67 and(gt(x, 2), gt(y, 2)), 68 and(gt(x, 3), gt(y, 3)), 69 and(gt(x, 4), gt(y, 4)), 70 and(gt(x, 5), gt(y, 5)), 71 and(gt(x, 6), gt(y, 6)), 72 and(gt(x, 7), gt(y, 7)), 73 and(gt(x, 8), gt(y, 8)), 74 and(gt(x, 9), gt(y, 9)), 75 and(lt(x, 1), lt(y, 1)), 76 and(lt(x, 2), lt(y, 2)), 77 and(lt(x, 3), lt(y, 3)), 78 and(lt(x, 4), lt(y, 4)), 79 and(lt(x, 5), lt(y, 5)), 80 and(lt(x, 6), lt(y, 6)), 81 and(lt(x, 7), lt(y, 7)), 82 and(lt(x, 8), lt(y, 8)), 83 and(lt(x, 9), lt(y, 9)), 84 ), 85 sql.RangeCollection{ 86 r(rgt(1), rgt(1)), 87 r(rgt(2), rgt(2)), 88 r(rgt(3), rgt(3)), 89 r(rgt(4), rgt(4)), 90 r(rgt(5), rgt(5)), 91 r(rgt(6), rgt(6)), 92 r(rgt(7), rgt(7)), 93 r(rgt(8), rgt(8)), 94 r(rgt(9), rgt(9)), 95 r(rlt(1), rlt(1)), 96 r(rlt(2), rlt(2)), 97 r(rlt(3), rlt(3)), 98 r(rlt(4), rlt(4)), 99 r(rlt(5), rlt(5)), 100 r(rlt(6), rlt(6)), 101 r(rlt(7), rlt(7)), 102 r(rlt(8), rlt(8)), 103 r(rlt(9), rlt(9)), 104 }, 105 }, 106 { 107 or( 108 and(gt(x, 2), gt(y, 2)), 109 and(eq(x, 4), eq(y, 4)), 110 and(lt(x, 9), lt(y, 9)), 111 and(eq(x, 6), eq(y, 6)), 112 and(eq(x, 8), eq(y, 8)), 113 ), 114 sql.RangeCollection{ 115 r(rgt(2), rgt(2)), 116 r(req(4), req(4)), 117 r(rlt(9), rlt(9)), 118 r(req(6), req(6)), 119 r(req(8), req(8)), 120 }, 121 }, 122 { 123 or( 124 and(gt(x, 2), gt(y, 2)), 125 and(eq(x, 4), eq(y, 4)), 126 and(lt(x, 9), lt(y, 9)), 127 and(eq(x, 6), eq(y, 6)), 128 and(eq(x, 8), eq(y, 8)), 129 ), 130 sql.RangeCollection{ 131 r(rgt(2), rgt(2)), 132 r(req(4), req(4)), 133 r(rlt(9), rlt(9)), 134 r(req(6), req(6)), 135 r(req(8), req(8)), 136 }, 137 }, 138 { 139 or( 140 and(cc(x, 2, 6), cc(y, 5, 10)), 141 and(cc(x, 3, 7), cc(y, 1, 4)), 142 and(oo(x, 4, 8), oo(y, 2, 5)), 143 and(oc(x, 5, 10), oc(y, 4, 7)), 144 ), 145 sql.RangeCollection{ 146 r(rcc(2, 6), rcc(5, 10)), 147 r(rcc(3, 7), rcc(1, 4)), 148 r(roo(4, 8), roo(2, 5)), 149 r(roc(5, 10), roc(4, 7)), 150 }, 151 }, 152 { 153 or( 154 and(cc(x, 1, 6), cc(y, 1, 3)), 155 and(cc(x, 1, 2), cc(y, 1, 3)), 156 and(cc(x, 3, 4), cc(y, 1, 3)), 157 and(cc(x, 5, 6), cc(y, 1, 3)), 158 and(cc(x, 2, 3), cc(y, 1, 2)), 159 ), 160 sql.RangeCollection{ 161 r(rcc(1, 6), rcc(1, 3)), 162 r(rcc(1, 2), rcc(1, 3)), 163 r(rcc(3, 4), rcc(1, 3)), 164 r(rcc(5, 6), rcc(1, 3)), 165 }, 166 }, 167 { 168 or( 169 and(cc(x, 1, 6), cc(y, 4, 7)), 170 and(cc(x, 4, 5), cc(y, 3, 8)), 171 and(cc(x, 3, 8), cc(y, 1, 6)), 172 ), 173 sql.RangeCollection{ 174 r(rcc(1, 6), rcc(4, 7)), 175 r(rcc(4, 5), rcc(3, 8)), 176 r(rcc(3, 8), rcc(1, 6)), 177 }, 178 }, 179 } 180 181 for _, test := range tests { 182 t.Run(fmt.Sprintf("Expr: %s\nRange: %s", test.reference.String(), test.ranges.DebugString()), func(t *testing.T) { 183 discreteRanges, err := sql.RemoveOverlappingRanges(test.ranges...) 184 require.NoError(t, err) 185 verificationRanges, err := removeOverlappingRangesVerification(test.ranges...) 186 require.NoError(t, err) 187 for _, row := range values2 { 188 referenceBool, err := test.reference.Eval(ctx, row) 189 require.NoError(t, err) 190 rangeBool := evalRanges(t, discreteRanges, row) 191 assert.Equal(t, referenceBool, rangeBool, fmt.Sprintf("%v: DiscreteRanges: %s", row, discreteRanges.DebugString())) 192 } 193 discreteRanges, err = sql.SortRanges(discreteRanges...) 194 require.NoError(t, err) 195 verificationRanges, err = sql.SortRanges(verificationRanges...) 196 require.NoError(t, err) 197 ok, err := discreteRanges.Equals(verificationRanges) 198 require.NoError(t, err) 199 assert.True(t, ok) 200 }) 201 } 202 } 203 204 func TestRangeOverlapThreeColumns(t *testing.T) { 205 ctx := sql.NewEmptyContext() 206 x, y, z, _, values3, _ := setup() 207 208 tests := []struct { 209 reference sql.Expression 210 ranges sql.RangeCollection 211 }{ 212 { 213 or( 214 and(gt(x, 2), gt(y, 2), gt(z, 2)), 215 and(lt(x, 8), lt(y, 8), lt(z, 8)), 216 ), 217 sql.RangeCollection{ 218 r(rgt(2), rgt(2), rgt(2)), 219 r(rlt(8), rlt(8), rlt(8)), 220 }, 221 }, 222 { 223 or( 224 and(gte(x, 3), gte(y, 3), gte(z, 3)), 225 and(lte(x, 5), lte(y, 5), lte(z, 5)), 226 ), 227 sql.RangeCollection{ 228 r(rgte(3), rgte(3), rgte(3)), 229 r(rlte(5), rlte(5), rlte(5)), 230 }, 231 }, 232 { 233 or( 234 and(gte(x, 3), gte(y, 4), gt(z, 5)), 235 and(lte(x, 6), lt(y, 7), lte(z, 8)), 236 ), 237 sql.RangeCollection{ 238 r(rgte(3), rgte(4), rgt(5)), 239 r(rlte(6), rlt(7), rlte(8)), 240 }, 241 }, 242 { 243 or( 244 and(gte(x, 4), gte(y, 4), gte(z, 3)), 245 and(lte(x, 4), lte(y, 4), lte(z, 5)), 246 ), 247 sql.RangeCollection{ 248 r(rgte(4), rgte(4), rgte(3)), 249 r(rlte(4), rlte(4), rlte(5)), 250 }, 251 }, 252 { 253 or( 254 and(gte(x, 4), gte(y, 3), gte(z, 4)), 255 and(lte(x, 4), lte(y, 5), lte(z, 4)), 256 ), 257 sql.RangeCollection{ 258 r(rgte(4), rgte(3), rgte(4)), 259 r(rlte(4), rlte(5), rlte(4)), 260 }, 261 }, 262 { 263 or( 264 and(gte(x, 3), gte(y, 4), gte(z, 4)), 265 and(lte(x, 5), lte(y, 4), lte(z, 4)), 266 ), 267 sql.RangeCollection{ 268 r(rgte(3), rgte(4), rgte(4)), 269 r(rlte(5), rlte(4), rlte(4)), 270 }, 271 }, 272 { 273 or( 274 and(lt(x, 4), gte(y, 3), lt(z, 4)), 275 and(gt(x, 4), lte(y, 5), gt(z, 4)), 276 ), 277 sql.RangeCollection{ 278 r(rlt(4), rgte(3), rlt(4)), 279 r(rgt(4), rlte(5), rgt(4)), 280 }, 281 }, 282 { 283 or( 284 and(gt(x, 3), gt(y, 2), eq(z, 2)), 285 and(lt(x, 4), gte(y, 7), lte(z, 2)), 286 and(lte(x, 9), gt(y, 5), gt(z, 1)), 287 ), 288 sql.RangeCollection{ 289 r(rgt(3), rgt(2), req(2)), 290 r(rlt(4), rgte(7), rlte(2)), 291 r(rlte(9), rgt(5), rgt(1)), 292 }, 293 }, 294 } 295 296 for _, test := range tests { 297 t.Run(fmt.Sprintf("Expr: %s\nRange: %s", test.reference.String(), test.ranges.DebugString()), func(t *testing.T) { 298 discreteRanges, err := sql.RemoveOverlappingRanges(test.ranges...) 299 require.NoError(t, err) 300 verificationRanges, err := removeOverlappingRangesVerification(test.ranges...) 301 require.NoError(t, err) 302 for _, row := range values3 { 303 referenceBool, err := test.reference.Eval(ctx, row) 304 require.NoError(t, err) 305 rangeBool := evalRanges(t, discreteRanges, row) 306 assert.Equal(t, referenceBool, rangeBool, fmt.Sprintf("%v: DiscreteRanges: %s", row, discreteRanges.DebugString())) 307 } 308 discreteRanges, err = sql.SortRanges(discreteRanges...) 309 require.NoError(t, err) 310 verificationRanges, err = sql.SortRanges(verificationRanges...) 311 require.NoError(t, err) 312 ok, err := discreteRanges.Equals(verificationRanges) 313 require.NoError(t, err) 314 assert.True(t, ok) 315 }) 316 } 317 } 318 319 func TestRangeOverlapNulls(t *testing.T) { 320 ctx := sql.NewEmptyContext() 321 x, y, _, _, _, valuesNull := setup() 322 323 tests := []struct { 324 reference sql.Expression 325 ranges sql.RangeCollection 326 }{ 327 { 328 reference: or( 329 and(isNull(x), gt(y, 5)), 330 ), 331 ranges: sql.RangeCollection{ 332 r(null(), rgt(5)), 333 }, 334 }, 335 { 336 reference: or( 337 and(isNull(x), isNotNull(y)), 338 ), 339 ranges: sql.RangeCollection{ 340 r(null(), notNull()), 341 }, 342 }, 343 { 344 reference: or( 345 and(isNull(x), lt(y, 5)), 346 ), 347 ranges: sql.RangeCollection{ 348 r(null(), rlt(5)), 349 }, 350 }, 351 { 352 reference: or( 353 and(isNull(x), gte(y, 5)), 354 ), 355 ranges: sql.RangeCollection{ 356 r(null(), rgte(5)), 357 }, 358 }, 359 { 360 reference: or( 361 and(isNull(x), lte(y, 5)), 362 ), 363 ranges: sql.RangeCollection{ 364 r(null(), rlte(5)), 365 }, 366 }, 367 { 368 reference: or( 369 and(isNull(x), lte(y, 5)), 370 ), 371 ranges: sql.RangeCollection{ 372 r(null(), rlte(5)), 373 }, 374 }, 375 { 376 reference: or( 377 and(isNull(x), eq(y, 1)), 378 ), 379 ranges: sql.RangeCollection{ 380 r(null(), req(1)), 381 }, 382 }, 383 } 384 385 for _, test := range tests { 386 t.Run(fmt.Sprintf("Expr: %s\nRange: %s", test.reference.String(), test.ranges.DebugString()), func(t *testing.T) { 387 discreteRanges, err := sql.RemoveOverlappingRanges(test.ranges...) 388 require.NoError(t, err) 389 verificationRanges, err := removeOverlappingRangesVerification(test.ranges...) 390 require.NoError(t, err) 391 for _, row := range valuesNull { 392 referenceBool, err := test.reference.Eval(ctx, row) 393 require.NoError(t, err) 394 rangeBool := evalRanges(t, discreteRanges, row) 395 assert.Equal(t, referenceBool, rangeBool, fmt.Sprintf("%v: DiscreteRanges: %s", row, discreteRanges.DebugString())) 396 } 397 discreteRanges, err = sql.SortRanges(discreteRanges...) 398 require.NoError(t, err) 399 verificationRanges, err = sql.SortRanges(verificationRanges...) 400 require.NoError(t, err) 401 ok, err := discreteRanges.Equals(verificationRanges) 402 require.NoError(t, err) 403 assert.True(t, ok) 404 }) 405 } 406 } 407 408 func TestComplexRange(t *testing.T) { 409 tests := []struct { 410 skip bool 411 ranges sql.RangeCollection 412 }{ 413 { 414 // derived from sqllogictest/index/in/100/slt_good_1.test:12655 415 ranges: sql.RangeCollection{ 416 r( 417 sql.RangeColumnExpr{LowerBound: sql.BelowNull{}, UpperBound: sql.AboveAll{}, Typ: types.Int16}, 418 sql.RangeColumnExpr{LowerBound: sql.BelowNull{}, UpperBound: sql.AboveAll{}, Typ: types.Int16}, 419 sql.RangeColumnExpr{LowerBound: sql.BelowNull{}, UpperBound: sql.AboveNull{}, Typ: types.Float32}, 420 ), 421 r( 422 sql.RangeColumnExpr{LowerBound: sql.AboveNull{}, UpperBound: sql.Below{Key: int16(848)}, Typ: types.Int16}, 423 sql.RangeColumnExpr{LowerBound: sql.Above{Key: int16(560)}, UpperBound: sql.AboveAll{}, Typ: types.Int16}, 424 sql.RangeColumnExpr{LowerBound: sql.BelowNull{}, UpperBound: sql.AboveAll{}, Typ: types.Float32}, 425 ), 426 r( 427 sql.RangeColumnExpr{LowerBound: sql.AboveNull{}, UpperBound: sql.Above{Key: 953}, Typ: types.Int16}, 428 sql.RangeColumnExpr{LowerBound: sql.BelowNull{}, UpperBound: sql.AboveAll{}, Typ: types.Int16}, 429 sql.RangeColumnExpr{LowerBound: sql.Below{Key: decimal.New(53978, -2)}, UpperBound: sql.AboveAll{}, Typ: types.Float32}, 430 ), 431 r( 432 sql.RangeColumnExpr{LowerBound: sql.Below{Key: int16(234)}, UpperBound: sql.Above{Key: int16(234)}, Typ: types.Int16}, 433 sql.RangeColumnExpr{LowerBound: sql.BelowNull{}, UpperBound: sql.AboveAll{}, Typ: types.Int16}, 434 sql.RangeColumnExpr{LowerBound: sql.Below{Key: decimal.New(48843, -2)}, UpperBound: sql.AboveAll{}, Typ: types.Float32}, 435 ), 436 r( 437 sql.RangeColumnExpr{LowerBound: sql.Below{Key: int16(258)}, UpperBound: sql.Above{Key: int16(258)}, Typ: types.Int16}, 438 sql.RangeColumnExpr{LowerBound: sql.BelowNull{}, UpperBound: sql.AboveAll{}, Typ: types.Int16}, 439 sql.RangeColumnExpr{LowerBound: sql.BelowNull{}, UpperBound: sql.AboveAll{}, Typ: types.Float32}, 440 ), 441 r( 442 sql.RangeColumnExpr{LowerBound: sql.Below{Key: int16(372)}, UpperBound: sql.Above{Key: int16(372)}, Typ: types.Int16}, 443 sql.RangeColumnExpr{LowerBound: sql.BelowNull{}, UpperBound: sql.AboveAll{}, Typ: types.Int16}, 444 sql.RangeColumnExpr{LowerBound: sql.Below{Key: decimal.New(48843, -2)}, UpperBound: sql.AboveAll{}, Typ: types.Float32}, 445 ), 446 r( 447 sql.RangeColumnExpr{LowerBound: sql.Below{Key: int16(583)}, UpperBound: sql.Above{Key: int16(583)}, Typ: types.Int16}, 448 sql.RangeColumnExpr{LowerBound: sql.BelowNull{}, UpperBound: sql.AboveAll{}, Typ: types.Int16}, 449 sql.RangeColumnExpr{LowerBound: sql.Below{Key: decimal.New(48843, -2)}, UpperBound: sql.AboveAll{}, Typ: types.Float32}, 450 ), 451 r( 452 sql.RangeColumnExpr{LowerBound: sql.Above{Key: int16(883)}, UpperBound: sql.AboveAll{}, Typ: types.Int16}, 453 sql.RangeColumnExpr{LowerBound: sql.BelowNull{}, UpperBound: sql.AboveAll{}, Typ: types.Int16}, 454 sql.RangeColumnExpr{LowerBound: sql.BelowNull{}, UpperBound: sql.AboveAll{}, Typ: types.Float32}, 455 ), 456 }, 457 }, 458 { 459 // derived from index query plan test 460 // `SELECT * FROM comp_index_t2 WHERE (((v1>25 AND v2 BETWEEN 23 AND 54) OR (v1<>40 AND v3>90)) OR (v1<>7 AND v4<=78));` 461 ranges: sql.RangeCollection{ 462 r( 463 sql.RangeColumnExpr{LowerBound: sql.Above{Key: 25}, UpperBound: sql.AboveAll{}, Typ: types.Int32}, 464 sql.RangeColumnExpr{LowerBound: sql.Below{Key: 23}, UpperBound: sql.Above{Key: 54}, Typ: types.Int32}, 465 sql.RangeColumnExpr{LowerBound: sql.BelowNull{}, UpperBound: sql.AboveAll{}, Typ: types.Int32}, 466 sql.RangeColumnExpr{LowerBound: sql.BelowNull{}, UpperBound: sql.AboveAll{}, Typ: types.Int32}, 467 ), 468 r( 469 sql.RangeColumnExpr{LowerBound: sql.Above{Key: 40}, UpperBound: sql.AboveAll{}, Typ: types.Int32}, 470 sql.RangeColumnExpr{LowerBound: sql.BelowNull{}, UpperBound: sql.AboveAll{}, Typ: types.Int32}, 471 sql.RangeColumnExpr{LowerBound: sql.Above{Key: 90}, UpperBound: sql.AboveAll{}, Typ: types.Int32}, 472 sql.RangeColumnExpr{LowerBound: sql.BelowNull{}, UpperBound: sql.AboveAll{}, Typ: types.Int32}, 473 ), 474 r( 475 sql.RangeColumnExpr{LowerBound: sql.AboveNull{}, UpperBound: sql.Below{Key: 40}, Typ: types.Int32}, 476 sql.RangeColumnExpr{LowerBound: sql.BelowNull{}, UpperBound: sql.AboveAll{}, Typ: types.Int32}, 477 sql.RangeColumnExpr{LowerBound: sql.Above{Key: 90}, UpperBound: sql.AboveAll{}, Typ: types.Int32}, 478 sql.RangeColumnExpr{LowerBound: sql.BelowNull{}, UpperBound: sql.AboveAll{}, Typ: types.Int32}, 479 ), 480 r( 481 sql.RangeColumnExpr{LowerBound: sql.Above{Key: 7}, UpperBound: sql.AboveAll{}, Typ: types.Int32}, 482 sql.RangeColumnExpr{LowerBound: sql.BelowNull{}, UpperBound: sql.AboveAll{}, Typ: types.Int32}, 483 sql.RangeColumnExpr{LowerBound: sql.BelowNull{}, UpperBound: sql.AboveAll{}, Typ: types.Int32}, 484 sql.RangeColumnExpr{LowerBound: sql.AboveNull{}, UpperBound: sql.Above{Key: 78}, Typ: types.Int32}, 485 ), 486 r( 487 sql.RangeColumnExpr{LowerBound: sql.AboveNull{}, UpperBound: sql.Below{Key: 7}, Typ: types.Int32}, 488 sql.RangeColumnExpr{LowerBound: sql.BelowNull{}, UpperBound: sql.AboveAll{}, Typ: types.Int32}, 489 sql.RangeColumnExpr{LowerBound: sql.BelowNull{}, UpperBound: sql.AboveAll{}, Typ: types.Int32}, 490 sql.RangeColumnExpr{LowerBound: sql.AboveNull{}, UpperBound: sql.Above{Key: 78}, Typ: types.Int32}, 491 ), 492 }, 493 }, 494 { 495 ranges: sql.RangeCollection{ 496 r( 497 sql.RangeColumnExpr{LowerBound: sql.Below{Key: 0}, UpperBound: sql.Above{Key: 6}, Typ: types.Int16}, 498 sql.RangeColumnExpr{LowerBound: sql.Below{Key: 0}, UpperBound: sql.Above{Key: 6}, Typ: types.Int16}, 499 sql.RangeColumnExpr{LowerBound: sql.Below{Key: 0}, UpperBound: sql.Above{Key: 0}, Typ: types.Int16}, 500 ), 501 r( 502 sql.RangeColumnExpr{LowerBound: sql.Above{Key: 0}, UpperBound: sql.Below{Key: 5}, Typ: types.Int16}, 503 sql.RangeColumnExpr{LowerBound: sql.Above{Key: 3}, UpperBound: sql.Above{Key: 6}, Typ: types.Int16}, 504 sql.RangeColumnExpr{LowerBound: sql.Below{Key: 0}, UpperBound: sql.Above{Key: 6}, Typ: types.Int16}, 505 ), 506 r( 507 sql.RangeColumnExpr{LowerBound: sql.Below{Key: 1}, UpperBound: sql.Above{Key: 1}, Typ: types.Int16}, 508 sql.RangeColumnExpr{LowerBound: sql.Below{Key: 0}, UpperBound: sql.Above{Key: 6}, Typ: types.Int16}, 509 sql.RangeColumnExpr{LowerBound: sql.Below{Key: 0}, UpperBound: sql.Above{Key: 6}, Typ: types.Int16}, 510 ), 511 r( 512 sql.RangeColumnExpr{LowerBound: sql.Below{Key: 2}, UpperBound: sql.Above{Key: 2}, Typ: types.Int16}, 513 sql.RangeColumnExpr{LowerBound: sql.Below{Key: 0}, UpperBound: sql.Above{Key: 6}, Typ: types.Int16}, 514 sql.RangeColumnExpr{LowerBound: sql.Below{Key: 1}, UpperBound: sql.Above{Key: 6}, Typ: types.Int16}, 515 ), 516 r( 517 sql.RangeColumnExpr{LowerBound: sql.Below{Key: 4}, UpperBound: sql.Above{Key: 4}, Typ: types.Int16}, 518 sql.RangeColumnExpr{LowerBound: sql.Below{Key: 0}, UpperBound: sql.Above{Key: 6}, Typ: types.Int16}, 519 sql.RangeColumnExpr{LowerBound: sql.Below{Key: 1}, UpperBound: sql.Above{Key: 6}, Typ: types.Int16}, 520 ), 521 }, 522 }, 523 { 524 ranges: sql.RangeCollection{ 525 r( 526 sql.RangeColumnExpr{LowerBound: sql.Below{Key: 69}, UpperBound: sql.Above{Key: 69}, Typ: types.Int32}, 527 sql.RangeColumnExpr{LowerBound: sql.BelowNull{}, UpperBound: sql.AboveAll{}, Typ: types.Float32}, 528 ), 529 r( 530 sql.RangeColumnExpr{LowerBound: sql.Below{Key: 73}, UpperBound: sql.Above{Key: 73}, Typ: types.Int32}, 531 sql.RangeColumnExpr{LowerBound: sql.BelowNull{}, UpperBound: sql.AboveAll{}, Typ: types.Float32}, 532 ), 533 r( 534 sql.RangeColumnExpr{LowerBound: sql.Below{Key: 12}, UpperBound: sql.Above{Key: 12}, Typ: types.Int32}, 535 sql.RangeColumnExpr{LowerBound: sql.BelowNull{}, UpperBound: sql.AboveAll{}, Typ: types.Float32}, 536 ), 537 r( 538 sql.RangeColumnExpr{LowerBound: sql.Below{Key: 3}, UpperBound: sql.Above{Key: 3}, Typ: types.Int32}, 539 sql.RangeColumnExpr{LowerBound: sql.BelowNull{}, UpperBound: sql.AboveAll{}, Typ: types.Float32}, 540 ), 541 r( 542 sql.RangeColumnExpr{LowerBound: sql.Below{Key: 17}, UpperBound: sql.Above{Key: 17}, Typ: types.Int32}, 543 sql.RangeColumnExpr{LowerBound: sql.BelowNull{}, UpperBound: sql.AboveAll{}, Typ: types.Float32}, 544 ), 545 r( 546 sql.RangeColumnExpr{LowerBound: sql.Below{Key: 70}, UpperBound: sql.Above{Key: 70}, Typ: types.Int32}, 547 sql.RangeColumnExpr{LowerBound: sql.BelowNull{}, UpperBound: sql.AboveAll{}, Typ: types.Float32}, 548 ), 549 r( 550 sql.RangeColumnExpr{LowerBound: sql.Below{Key: 20}, UpperBound: sql.Above{Key: 20}, Typ: types.Int32}, 551 sql.RangeColumnExpr{LowerBound: sql.BelowNull{}, UpperBound: sql.AboveAll{}, Typ: types.Float32}, 552 ), 553 r( 554 sql.RangeColumnExpr{LowerBound: sql.Below{Key: 4}, UpperBound: sql.Above{Key: 4}, Typ: types.Int32}, 555 sql.RangeColumnExpr{LowerBound: sql.BelowNull{}, UpperBound: sql.AboveAll{}, Typ: types.Float32}, 556 ), 557 r( 558 sql.RangeColumnExpr{LowerBound: sql.Below{Key: 39}, UpperBound: sql.Above{Key: 39}, Typ: types.Int32}, 559 sql.RangeColumnExpr{LowerBound: sql.BelowNull{}, UpperBound: sql.AboveAll{}, Typ: types.Float32}, 560 ), 561 r( 562 sql.RangeColumnExpr{LowerBound: sql.BelowNull{}, UpperBound: sql.AboveAll{}, Typ: types.Int32}, 563 sql.RangeColumnExpr{LowerBound: sql.AboveNull{}, UpperBound: sql.Below{Key: 69.67}, Typ: types.Float32}, 564 ), 565 }, 566 }, 567 } 568 569 for _, test := range tests { 570 t.Run(fmt.Sprintf("Range: %s", test.ranges.DebugString()), func(t *testing.T) { 571 if test.skip { 572 t.Skip() 573 } 574 discreteRanges, err := sql.RemoveOverlappingRanges(test.ranges...) 575 require.NoError(t, err) 576 verificationRanges, err := removeOverlappingRangesVerification(test.ranges...) 577 require.NoError(t, err) 578 discreteRanges, err = sql.SortRanges(discreteRanges...) 579 require.NoError(t, err) 580 verificationRanges, err = sql.SortRanges(verificationRanges...) 581 require.NoError(t, err) 582 ok, err := discreteRanges.Equals(verificationRanges) 583 require.NoError(t, err) 584 assert.True(t, ok) 585 if !ok { 586 t.Logf("DiscreteRanges: %s", discreteRanges.DebugString()) 587 t.Logf("VerificationRanges: %s", verificationRanges.DebugString()) 588 } 589 590 // TODO: need a way to either verify that the ranges cover the area, or that they're the same 591 for i := 0; i < len(discreteRanges)-1; i++ { 592 for j := i + 1; j < len(discreteRanges); j++ { 593 r1 := discreteRanges[i] 594 r2 := discreteRanges[j] 595 hasOverlap, err := r1.Overlaps(r2) 596 if hasOverlap { 597 t.Logf("Overlap: %s\n%s", r1.String(), r2.String()) 598 } 599 assert.NoError(t, err) 600 assert.False(t, hasOverlap) 601 } 602 } 603 }) 604 } 605 } 606 607 func setup() (x, y, z sql.Expression, values2, values3, valuesNull [][]interface{}) { 608 values2 = make([][]interface{}, 0, 100) 609 values3 = make([][]interface{}, 0, 1000) 610 for i := byte(1); i <= 10; i++ { 611 for j := byte(1); j <= 10; j++ { 612 for k := byte(1); k <= 10; k++ { 613 values3 = append(values3, []interface{}{i, j, k}) 614 } 615 values2 = append(values2, []interface{}{i, j}) 616 if i%2 == 0 { 617 valuesNull = append(valuesNull, []interface{}{nil, j}) 618 } else { 619 valuesNull = append(valuesNull, []interface{}{i, j}) 620 } 621 } 622 } 623 x = expression.NewGetField(0, rangeType, "x", true) 624 y = expression.NewGetField(1, rangeType, "y", true) 625 z = expression.NewGetField(2, rangeType, "z", true) 626 return 627 } 628 629 func evalRanges(t *testing.T, ranges []sql.Range, row []interface{}) bool { 630 found := false 631 for _, rang := range ranges { 632 if evalRange(t, rang, row) { 633 if !found { 634 found = true 635 } else { 636 assert.FailNow(t, "overlap in ranges") 637 } 638 } 639 } 640 return found 641 } 642 643 func evalRange(t *testing.T, rang sql.Range, row []interface{}) bool { 644 rowRange := make(sql.Range, len(rang)) 645 for i, val := range row { 646 if val == nil { 647 rowRange[i] = sql.NullRangeColumnExpr(rangeType) 648 } else { 649 rowRange[i] = sql.ClosedRangeColumnExpr(val, val, rangeType) 650 } 651 } 652 ok, err := rang.IsSupersetOf(rowRange) 653 require.NoError(t, err) 654 return ok 655 } 656 657 func removeOverlappingRangesVerification(ranges ...sql.Range) (sql.RangeCollection, error) { 658 if len(ranges) == 0 { 659 return nil, nil 660 } 661 662 var newRanges sql.RangeCollection 663 for i := 0; i < len(ranges); i++ { 664 hadOverlap := false 665 for nri := 0; nri < len(newRanges); nri++ { 666 if resultingRanges, ok, err := ranges[i].RemoveOverlap(newRanges[nri]); err != nil { 667 return nil, err 668 } else if ok { 669 hadOverlap = true 670 // Remove the overlapping Range from newRanges 671 nrLast := len(newRanges) - 1 672 newRanges[nri], newRanges[nrLast] = newRanges[nrLast], newRanges[nri] 673 newRanges = newRanges[:nrLast] 674 // Add the new ranges to the end of the given slice allowing us to compare those against everything else. 675 ranges = append(ranges, resultingRanges...) 676 break 677 } 678 } 679 if !hadOverlap { 680 newRanges = append(newRanges, ranges[i]) 681 } 682 } 683 684 return newRanges, nil 685 } 686 687 func eq(field sql.Expression, val uint8) sql.Expression { 688 return expression.NewNullSafeEquals(field, expression.NewLiteral(val, rangeType)) 689 } 690 691 func lt(field sql.Expression, val uint8) sql.Expression { 692 return expression.NewLessThan(field, expression.NewLiteral(val, rangeType)) 693 } 694 695 func lte(field sql.Expression, val uint8) sql.Expression { 696 return expression.NewLessThanOrEqual(field, expression.NewLiteral(val, rangeType)) 697 } 698 699 func gt(field sql.Expression, val uint8) sql.Expression { 700 return expression.NewGreaterThan(field, expression.NewLiteral(val, rangeType)) 701 } 702 703 func gte(field sql.Expression, val uint8) sql.Expression { 704 return expression.NewGreaterThanOrEqual(field, expression.NewLiteral(val, rangeType)) 705 } 706 707 func isNull(field sql.Expression) sql.Expression { 708 return expression.NewIsNull(field) 709 } 710 711 func isNotNull(field sql.Expression) sql.Expression { 712 return expression.NewNot(expression.NewIsNull(field)) 713 } 714 715 func cc(field sql.Expression, lowerbound, upperbound uint8) sql.Expression { 716 return and( 717 expression.NewGreaterThanOrEqual(field, expression.NewLiteral(lowerbound, rangeType)), 718 expression.NewLessThanOrEqual(field, expression.NewLiteral(upperbound, rangeType)), 719 ) 720 } 721 722 func co(field sql.Expression, lowerbound, upperbound uint8) sql.Expression { 723 return and( 724 expression.NewGreaterThanOrEqual(field, expression.NewLiteral(lowerbound, rangeType)), 725 expression.NewLessThan(field, expression.NewLiteral(upperbound, rangeType)), 726 ) 727 } 728 729 func oc(field sql.Expression, lowerbound, upperbound uint8) sql.Expression { 730 return and( 731 expression.NewGreaterThan(field, expression.NewLiteral(lowerbound, rangeType)), 732 expression.NewLessThanOrEqual(field, expression.NewLiteral(upperbound, rangeType)), 733 ) 734 } 735 736 func oo(field sql.Expression, lowerbound, upperbound uint8) sql.Expression { 737 return and( 738 expression.NewGreaterThan(field, expression.NewLiteral(lowerbound, rangeType)), 739 expression.NewLessThan(field, expression.NewLiteral(upperbound, rangeType)), 740 ) 741 } 742 743 func not(field sql.Expression, val uint8) sql.Expression { 744 return expression.NewNot(eq(field, val)) 745 } 746 747 func r(colExprs ...sql.RangeColumnExpr) sql.Range { 748 return colExprs 749 } 750 751 func req(val byte) sql.RangeColumnExpr { 752 return sql.ClosedRangeColumnExpr(val, val, rangeType) 753 } 754 755 func rlt(val byte) sql.RangeColumnExpr { 756 return sql.LessThanRangeColumnExpr(val, rangeType) 757 } 758 759 func rlte(val byte) sql.RangeColumnExpr { 760 return sql.LessOrEqualRangeColumnExpr(val, rangeType) 761 } 762 763 func rgt(val byte) sql.RangeColumnExpr { 764 return sql.GreaterThanRangeColumnExpr(val, rangeType) 765 } 766 767 func rgte(val byte) sql.RangeColumnExpr { 768 return sql.GreaterOrEqualRangeColumnExpr(val, rangeType) 769 } 770 771 func null() sql.RangeColumnExpr { 772 return sql.NullRangeColumnExpr(rangeType) 773 } 774 775 func notNull() sql.RangeColumnExpr { 776 return sql.NotNullRangeColumnExpr(rangeType) 777 } 778 779 func rcc(lowerbound, upperbound byte) sql.RangeColumnExpr { 780 return sql.CustomRangeColumnExpr(lowerbound, upperbound, sql.Closed, sql.Closed, rangeType) 781 } 782 783 func rco(lowerbound, upperbound byte) sql.RangeColumnExpr { 784 return sql.CustomRangeColumnExpr(lowerbound, upperbound, sql.Closed, sql.Open, rangeType) 785 } 786 787 func roc(lowerbound, upperbound byte) sql.RangeColumnExpr { 788 return sql.CustomRangeColumnExpr(lowerbound, upperbound, sql.Open, sql.Closed, rangeType) 789 } 790 791 func roo(lowerbound, upperbound byte) sql.RangeColumnExpr { 792 return sql.CustomRangeColumnExpr(lowerbound, upperbound, sql.Open, sql.Open, rangeType) 793 } 794 795 func or(expressions ...sql.Expression) sql.Expression { 796 if len(expressions) == 1 { 797 return expressions[0] 798 } 799 if expressions[0] == nil { 800 return or(expressions[1:]...) 801 } 802 return expression.NewOr(expressions[0], or(expressions[1:]...)) 803 } 804 805 func and(expressions ...sql.Expression) sql.Expression { 806 if len(expressions) == 1 { 807 return expressions[0] 808 } 809 if expressions[0] == nil { 810 return and(expressions[1:]...) 811 } 812 return expression.NewAnd(expressions[0], and(expressions[1:]...)) 813 } 814 815 func buildTestRangeTree(ranges []sql.Range) (*sql.RangeColumnExprTree, error) { 816 tree, err := sql.NewRangeColumnExprTree(ranges[0], []sql.Type{rangeType}) 817 if err != nil { 818 return nil, err 819 } 820 for _, rng := range ranges[1:] { 821 err = tree.Insert(rng) 822 if err != nil { 823 return nil, err 824 } 825 } 826 return tree, nil 827 } 828 829 func TestRangeTreeInsert(t *testing.T) { 830 tests := []struct { 831 name string 832 setupRngs []sql.Range 833 setupExp string 834 rng sql.Range 835 exp string 836 }{ 837 { 838 name: "insert smallest", 839 setupRngs: []sql.Range{r(req(7)), r(req(3)), r(req(11))}, 840 setupExp: "RangeColumnExprTree\n" + 841 "│ ┌── [11, 11] max: Above[11] color: 1\n" + 842 "└── [7, 7] max: Above[11] color: 0\n" + 843 " └── [3, 3] max: Above[3] color: 1\n" + 844 "", 845 rng: r(req(0)), 846 exp: "RangeColumnExprTree\n" + 847 "│ ┌── [11, 11] max: Above[11] color: 0\n" + 848 "└── [7, 7] max: Above[11] color: 0\n" + 849 " └── [3, 3] max: Above[3] color: 0\n" + 850 " └── [0, 0] max: Above[0] color: 1\n" + 851 "", 852 }, 853 { 854 name: "insert largest", 855 setupRngs: []sql.Range{r(req(7)), r(req(3)), r(req(11))}, 856 setupExp: "RangeColumnExprTree\n" + 857 "│ ┌── [11, 11] max: Above[11] color: 1\n" + 858 "└── [7, 7] max: Above[11] color: 0\n" + 859 " └── [3, 3] max: Above[3] color: 1\n" + 860 "", 861 rng: r(req(14)), 862 exp: "RangeColumnExprTree\n" + 863 "│ ┌── [14, 14] max: Above[14] color: 1\n" + 864 "│ ┌── [11, 11] max: Above[14] color: 0\n" + 865 "└── [7, 7] max: Above[14] color: 0\n" + 866 " └── [3, 3] max: Above[3] color: 0\n" + 867 "", 868 }, 869 { 870 name: "insert rebalance left child", 871 setupRngs: []sql.Range{r(req(7)), r(req(3)), r(req(11)), r(req(0))}, 872 setupExp: "RangeColumnExprTree\n" + 873 "│ ┌── [11, 11] max: Above[11] color: 0\n" + 874 "└── [7, 7] max: Above[11] color: 0\n" + 875 " └── [3, 3] max: Above[3] color: 0\n" + 876 " └── [0, 0] max: Above[0] color: 1\n" + 877 "", 878 rng: r(req(1)), 879 exp: "RangeColumnExprTree\n" + 880 "│ ┌── [11, 11] max: Above[11] color: 0\n" + 881 "└── [7, 7] max: Above[11] color: 0\n" + 882 " │ ┌── [3, 3] max: Above[3] color: 1\n" + 883 " └── [1, 1] max: Above[3] color: 0\n" + 884 " └── [0, 0] max: Above[0] color: 1\n" + 885 "", 886 }, 887 { 888 name: "insert rebalance right child", 889 setupRngs: []sql.Range{r(req(7)), r(req(3)), r(req(11)), r(req(12))}, 890 setupExp: "RangeColumnExprTree\n" + 891 "│ ┌── [12, 12] max: Above[12] color: 1\n" + 892 "│ ┌── [11, 11] max: Above[12] color: 0\n" + 893 "└── [7, 7] max: Above[12] color: 0\n" + 894 " └── [3, 3] max: Above[3] color: 0\n" + 895 "", 896 rng: r(req(13)), 897 exp: "RangeColumnExprTree\n" + 898 "│ ┌── [13, 13] max: Above[13] color: 1\n" + 899 "│ ┌── [12, 12] max: Above[13] color: 0\n" + 900 "│ │ └── [11, 11] max: Above[11] color: 1\n" + 901 "└── [7, 7] max: Above[13] color: 0\n" + 902 " └── [3, 3] max: Above[3] color: 0\n" + 903 "", 904 }, 905 { 906 name: "insert rebalance root from left", 907 setupRngs: []sql.Range{r(req(7)), r(req(3)), r(req(11)), r(req(0)), r(req(1)), r(req(2)), r(req(4))}, 908 setupExp: "RangeColumnExprTree\n" + 909 "│ ┌── [11, 11] max: Above[11] color: 0\n" + 910 "└── [7, 7] max: Above[11] color: 0\n" + 911 " │ ┌── [4, 4] max: Above[4] color: 1\n" + 912 " │ ┌── [3, 3] max: Above[4] color: 0\n" + 913 " │ │ └── [2, 2] max: Above[2] color: 1\n" + 914 " └── [1, 1] max: Above[4] color: 1\n" + 915 " └── [0, 0] max: Above[0] color: 0\n" + 916 "", 917 rng: r(req(5)), 918 exp: "RangeColumnExprTree\n" + 919 "│ ┌── [11, 11] max: Above[11] color: 0\n" + 920 "│ ┌── [7, 7] max: Above[11] color: 1\n" + 921 "│ │ │ ┌── [5, 5] max: Above[5] color: 1\n" + 922 "│ │ └── [4, 4] max: Above[5] color: 0\n" + 923 "└── [3, 3] max: Above[11] color: 0\n" + 924 " │ ┌── [2, 2] max: Above[2] color: 0\n" + 925 " └── [1, 1] max: Above[2] color: 1\n" + 926 " └── [0, 0] max: Above[0] color: 0\n" + 927 "", 928 }, 929 { 930 name: "insert rebalance root from right", 931 setupRngs: []sql.Range{r(req(7)), r(req(3)), r(req(11)), r(req(8)), r(req(9)), r(req(10)), r(req(12))}, 932 setupExp: "RangeColumnExprTree\n" + 933 "│ ┌── [12, 12] max: Above[12] color: 1\n" + 934 "│ ┌── [11, 11] max: Above[12] color: 0\n" + 935 "│ │ └── [10, 10] max: Above[10] color: 1\n" + 936 "│ ┌── [9, 9] max: Above[12] color: 1\n" + 937 "│ │ └── [8, 8] max: Above[8] color: 0\n" + 938 "└── [7, 7] max: Above[12] color: 0\n" + 939 " └── [3, 3] max: Above[3] color: 0\n" + 940 "", 941 rng: r(req(13)), 942 exp: "RangeColumnExprTree\n" + 943 "│ ┌── [13, 13] max: Above[13] color: 1\n" + 944 "│ ┌── [12, 12] max: Above[13] color: 0\n" + 945 "│ ┌── [11, 11] max: Above[13] color: 1\n" + 946 "│ │ └── [10, 10] max: Above[10] color: 0\n" + 947 "└── [9, 9] max: Above[13] color: 0\n" + 948 " │ ┌── [8, 8] max: Above[8] color: 0\n" + 949 " └── [7, 7] max: Above[8] color: 1\n" + 950 " └── [3, 3] max: Above[3] color: 0\n" + 951 "", 952 }, 953 { 954 name: "insert smallest", 955 setupRngs: []sql.Range{r(rcc(4, 6)), r(req(3)), r(req(11))}, 956 setupExp: "RangeColumnExprTree\n" + 957 "│ ┌── [11, 11] max: Above[11] color: 1\n" + 958 "└── [4, 6] max: Above[11] color: 0\n" + 959 " └── [3, 3] max: Above[3] color: 1\n" + 960 "", 961 rng: r(req(0)), 962 exp: "RangeColumnExprTree\n" + 963 "│ ┌── [11, 11] max: Above[11] color: 0\n" + 964 "└── [4, 6] max: Above[11] color: 0\n" + 965 " └── [3, 3] max: Above[3] color: 0\n" + 966 " └── [0, 0] max: Above[0] color: 1\n" + 967 "", 968 }, 969 { 970 name: "insert compare above and below", 971 setupRngs: []sql.Range{r(roo(4, 6)), r(req(4))}, 972 setupExp: "RangeColumnExprTree\n" + 973 "└── (4, 6) max: Below[6] color: 0\n" + 974 " └── [4, 4] max: Above[4] color: 1\n" + 975 "", 976 rng: r(req(6)), 977 exp: "RangeColumnExprTree\n" + 978 "│ ┌── [6, 6] max: Above[6] color: 1\n" + 979 "└── (4, 6) max: Above[6] color: 0\n" + 980 " └── [4, 4] max: Above[4] color: 1\n" + 981 "", 982 }, 983 } 984 985 for _, test := range tests { 986 t.Run(test.name, func(t *testing.T) { 987 tree, err := buildTestRangeTree(test.setupRngs) 988 require.NoError(t, err) 989 assert.Equal(t, test.setupExp, tree.String()) 990 991 err = tree.Insert(test.rng) 992 require.NoError(t, err) 993 assert.Equal(t, test.exp, tree.String()) 994 }) 995 } 996 } 997 998 func TestRangeTreeRemove(t *testing.T) { 999 tests := []struct { 1000 name string 1001 setupRngs []sql.Range 1002 setupExp string 1003 rng sql.Range 1004 exp string 1005 }{ 1006 { 1007 name: "remove smallest", 1008 setupRngs: []sql.Range{r(req(7)), r(req(3)), r(req(11)), r(req(1)), r(req(5)), r(req(9)), r(req(13))}, 1009 setupExp: "RangeColumnExprTree\n" + 1010 "│ ┌── [13, 13] max: Above[13] color: 1\n" + 1011 "│ ┌── [11, 11] max: Above[13] color: 0\n" + 1012 "│ │ └── [9, 9] max: Above[9] color: 1\n" + 1013 "└── [7, 7] max: Above[13] color: 0\n" + 1014 " │ ┌── [5, 5] max: Above[5] color: 1\n" + 1015 " └── [3, 3] max: Above[5] color: 0\n" + 1016 " └── [1, 1] max: Above[1] color: 1\n" + 1017 "", 1018 rng: r(req(1)), 1019 exp: "RangeColumnExprTree\n" + 1020 "│ ┌── [13, 13] max: Above[13] color: 1\n" + 1021 "│ ┌── [11, 11] max: Above[13] color: 0\n" + 1022 "│ │ └── [9, 9] max: Above[9] color: 1\n" + 1023 "└── [7, 7] max: Above[13] color: 0\n" + 1024 " │ ┌── [5, 5] max: Above[5] color: 1\n" + 1025 " └── [3, 3] max: Above[5] color: 0\n" + 1026 "", 1027 }, 1028 { 1029 name: "remove largest", 1030 setupRngs: []sql.Range{r(req(7)), r(req(3)), r(req(11)), r(req(1)), r(req(5)), r(req(9)), r(req(13))}, 1031 setupExp: "RangeColumnExprTree\n" + 1032 "│ ┌── [13, 13] max: Above[13] color: 1\n" + 1033 "│ ┌── [11, 11] max: Above[13] color: 0\n" + 1034 "│ │ └── [9, 9] max: Above[9] color: 1\n" + 1035 "└── [7, 7] max: Above[13] color: 0\n" + 1036 " │ ┌── [5, 5] max: Above[5] color: 1\n" + 1037 " └── [3, 3] max: Above[5] color: 0\n" + 1038 " └── [1, 1] max: Above[1] color: 1\n" + 1039 "", 1040 rng: r(req(13)), 1041 exp: "RangeColumnExprTree\n" + 1042 "│ ┌── [11, 11] max: Above[11] color: 0\n" + 1043 "│ │ └── [9, 9] max: Above[9] color: 1\n" + 1044 "└── [7, 7] max: Above[11] color: 0\n" + 1045 " │ ┌── [5, 5] max: Above[5] color: 1\n" + 1046 " └── [3, 3] max: Above[5] color: 0\n" + 1047 " └── [1, 1] max: Above[1] color: 1\n" + 1048 "", 1049 }, 1050 { 1051 name: "remove largest without left child", 1052 setupRngs: []sql.Range{r(req(7)), r(req(3)), r(req(11)), r(req(1)), r(req(5)), r(req(13))}, 1053 setupExp: "RangeColumnExprTree\n" + 1054 "│ ┌── [13, 13] max: Above[13] color: 1\n" + 1055 "│ ┌── [11, 11] max: Above[13] color: 0\n" + 1056 "└── [7, 7] max: Above[13] color: 0\n" + 1057 " │ ┌── [5, 5] max: Above[5] color: 1\n" + 1058 " └── [3, 3] max: Above[5] color: 0\n" + 1059 " └── [1, 1] max: Above[1] color: 1\n" + 1060 "", 1061 rng: r(req(13)), 1062 exp: "RangeColumnExprTree\n" + 1063 "│ ┌── [11, 11] max: Above[11] color: 0\n" + 1064 "└── [7, 7] max: Above[11] color: 0\n" + 1065 " │ ┌── [5, 5] max: Above[5] color: 1\n" + 1066 " └── [3, 3] max: Above[5] color: 0\n" + 1067 " └── [1, 1] max: Above[1] color: 1\n" + 1068 "", 1069 }, 1070 { 1071 name: "remove left parent", 1072 setupRngs: []sql.Range{r(req(7)), r(req(3)), r(req(11)), r(req(1)), r(req(5)), r(req(9)), r(req(13))}, 1073 setupExp: "RangeColumnExprTree\n" + 1074 "│ ┌── [13, 13] max: Above[13] color: 1\n" + 1075 "│ ┌── [11, 11] max: Above[13] color: 0\n" + 1076 "│ │ └── [9, 9] max: Above[9] color: 1\n" + 1077 "└── [7, 7] max: Above[13] color: 0\n" + 1078 " │ ┌── [5, 5] max: Above[5] color: 1\n" + 1079 " └── [3, 3] max: Above[5] color: 0\n" + 1080 " └── [1, 1] max: Above[1] color: 1\n" + 1081 "", 1082 rng: r(req(3)), 1083 exp: "RangeColumnExprTree\n" + 1084 "│ ┌── [13, 13] max: Above[13] color: 1\n" + 1085 "│ ┌── [11, 11] max: Above[13] color: 0\n" + 1086 "│ │ └── [9, 9] max: Above[9] color: 1\n" + 1087 "└── [7, 7] max: Above[13] color: 0\n" + 1088 " │ ┌── [5, 5] max: Above[5] color: 1\n" + 1089 " └── [1, 1] max: Above[5] color: 0\n" + 1090 "", 1091 }, 1092 { 1093 name: "remove right parent", 1094 setupRngs: []sql.Range{r(req(7)), r(req(3)), r(req(11)), r(req(1)), r(req(5)), r(req(9)), r(req(13))}, 1095 setupExp: "RangeColumnExprTree\n" + 1096 "│ ┌── [13, 13] max: Above[13] color: 1\n" + 1097 "│ ┌── [11, 11] max: Above[13] color: 0\n" + 1098 "│ │ └── [9, 9] max: Above[9] color: 1\n" + 1099 "└── [7, 7] max: Above[13] color: 0\n" + 1100 " │ ┌── [5, 5] max: Above[5] color: 1\n" + 1101 " └── [3, 3] max: Above[5] color: 0\n" + 1102 " └── [1, 1] max: Above[1] color: 1\n" + 1103 "", 1104 rng: r(req(11)), 1105 exp: "RangeColumnExprTree\n" + 1106 "│ ┌── [13, 13] max: Above[13] color: 1\n" + 1107 "│ ┌── [9, 9] max: Above[13] color: 0\n" + 1108 "└── [7, 7] max: Above[13] color: 0\n" + 1109 " │ ┌── [5, 5] max: Above[5] color: 1\n" + 1110 " └── [3, 3] max: Above[5] color: 0\n" + 1111 " └── [1, 1] max: Above[1] color: 1\n" + 1112 "", 1113 }, 1114 { 1115 name: "remove root", 1116 setupRngs: []sql.Range{r(req(7)), r(req(3)), r(req(11)), r(req(1)), r(req(5)), r(req(9)), r(req(13))}, 1117 setupExp: "RangeColumnExprTree\n" + 1118 "│ ┌── [13, 13] max: Above[13] color: 1\n" + 1119 "│ ┌── [11, 11] max: Above[13] color: 0\n" + 1120 "│ │ └── [9, 9] max: Above[9] color: 1\n" + 1121 "└── [7, 7] max: Above[13] color: 0\n" + 1122 " │ ┌── [5, 5] max: Above[5] color: 1\n" + 1123 " └── [3, 3] max: Above[5] color: 0\n" + 1124 " └── [1, 1] max: Above[1] color: 1\n" + 1125 "", 1126 rng: r(req(7)), 1127 exp: "RangeColumnExprTree\n" + 1128 "│ ┌── [13, 13] max: Above[13] color: 1\n" + 1129 "│ ┌── [11, 11] max: Above[13] color: 0\n" + 1130 "│ │ └── [9, 9] max: Above[9] color: 1\n" + 1131 "└── [5, 5] max: Above[13] color: 0\n" + 1132 " └── [3, 3] max: Above[3] color: 0\n" + 1133 " └── [1, 1] max: Above[1] color: 1\n" + 1134 "", 1135 }, 1136 { 1137 name: "remove rotate left", 1138 setupRngs: []sql.Range{r(req(7)), r(req(3)), r(req(11)), r(req(1)), r(req(5))}, 1139 setupExp: "RangeColumnExprTree\n" + 1140 "│ ┌── [11, 11] max: Above[11] color: 0\n" + 1141 "└── [7, 7] max: Above[11] color: 0\n" + 1142 " │ ┌── [5, 5] max: Above[5] color: 1\n" + 1143 " └── [3, 3] max: Above[5] color: 0\n" + 1144 " └── [1, 1] max: Above[1] color: 1\n" + 1145 "", 1146 rng: r(req(11)), 1147 exp: "RangeColumnExprTree\n" + 1148 "│ ┌── [7, 7] max: Above[7] color: 0\n" + 1149 "│ │ └── [5, 5] max: Above[5] color: 1\n" + 1150 "└── [3, 3] max: Above[7] color: 0\n" + 1151 " └── [1, 1] max: Above[1] color: 0\n" + 1152 "", 1153 }, 1154 { 1155 name: "remove root", 1156 setupRngs: []sql.Range{r(req(7)), r(req(3)), r(req(11)), r(req(9)), r(req(13))}, 1157 setupExp: "RangeColumnExprTree\n" + 1158 "│ ┌── [13, 13] max: Above[13] color: 1\n" + 1159 "│ ┌── [11, 11] max: Above[13] color: 0\n" + 1160 "│ │ └── [9, 9] max: Above[9] color: 1\n" + 1161 "└── [7, 7] max: Above[13] color: 0\n" + 1162 " └── [3, 3] max: Above[3] color: 0\n" + 1163 "", 1164 rng: r(req(3)), 1165 exp: "RangeColumnExprTree\n" + 1166 "│ ┌── [13, 13] max: Above[13] color: 0\n" + 1167 "└── [11, 11] max: Above[13] color: 0\n" + 1168 " │ ┌── [9, 9] max: Above[9] color: 1\n" + 1169 " └── [7, 7] max: Above[9] color: 0\n" + 1170 "", 1171 }, 1172 { 1173 name: "remove ranges", 1174 setupRngs: []sql.Range{r(roo(3, 5)), r(roo(1, 3)), r(roo(5, 7))}, 1175 setupExp: "RangeColumnExprTree\n" + 1176 "│ ┌── (5, 7) max: Below[7] color: 1\n" + 1177 "└── (3, 5) max: Below[7] color: 0\n" + 1178 " └── (1, 3) max: Below[3] color: 1\n" + 1179 "", 1180 rng: r(roo(1, 3)), 1181 exp: "RangeColumnExprTree\n" + 1182 "│ ┌── (5, 7) max: Below[7] color: 1\n" + 1183 "└── (3, 5) max: Below[7] color: 0\n" + 1184 "", 1185 }, 1186 { 1187 name: "remove ranges", 1188 setupRngs: []sql.Range{r(roo(3, 5)), r(roo(1, 3)), r(roo(5, 7))}, 1189 setupExp: "RangeColumnExprTree\n" + 1190 "│ ┌── (5, 7) max: Below[7] color: 1\n" + 1191 "└── (3, 5) max: Below[7] color: 0\n" + 1192 " └── (1, 3) max: Below[3] color: 1\n" + 1193 "", 1194 rng: r(roo(3, 5)), 1195 exp: "RangeColumnExprTree\n" + 1196 "│ ┌── (5, 7) max: Below[7] color: 1\n" + 1197 "└── (1, 3) max: Below[7] color: 0\n" + 1198 "", 1199 }, 1200 } 1201 1202 for _, test := range tests { 1203 t.Run(test.name, func(t *testing.T) { 1204 tree, err := buildTestRangeTree(test.setupRngs) 1205 require.NoError(t, err) 1206 assert.Equal(t, test.setupExp, tree.String()) 1207 1208 err = tree.Remove(test.rng) 1209 require.NoError(t, err) 1210 assert.Equal(t, test.exp, tree.String()) 1211 }) 1212 } 1213 }