github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/opt/props/physical/ordering_choice_test.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_test 12 13 import ( 14 "testing" 15 16 "github.com/cockroachdb/cockroach/pkg/sql/opt" 17 "github.com/cockroachdb/cockroach/pkg/sql/opt/props" 18 "github.com/cockroachdb/cockroach/pkg/sql/opt/props/physical" 19 ) 20 21 func TestOrderingChoice_FromOrdering(t *testing.T) { 22 var oc physical.OrderingChoice 23 oc.FromOrdering(opt.Ordering{1, -2, 3}) 24 if exp, actual := "+1,-2,+3", oc.String(); exp != actual { 25 t.Errorf("expected %s, got %s", exp, actual) 26 } 27 28 oc.FromOrderingWithOptCols(opt.Ordering{1, -2, 3, 4, -5}, opt.MakeColSet(1, 3, 5)) 29 if exp, actual := "-2,+4 opt(1,3,5)", oc.String(); exp != actual { 30 t.Errorf("expected %s, got %s", exp, actual) 31 } 32 } 33 34 func TestOrderingChoice_ToOrdering(t *testing.T) { 35 testcases := []struct { 36 s string 37 o opt.Ordering 38 }{ 39 {s: " ", o: opt.Ordering{}}, 40 {s: "+1", o: opt.Ordering{1}}, 41 {s: "-1,+(2|3) opt(4,5)", o: opt.Ordering{-1, 2}}, 42 {s: "+(1|2),-(3|4),+5", o: opt.Ordering{1, -3, 5}}, 43 } 44 45 for _, tc := range testcases { 46 choice := physical.ParseOrderingChoice(tc.s) 47 ordering := choice.ToOrdering() 48 if len(ordering) != len(tc.o) { 49 t.Errorf("%s: expected %s, actual: %s", tc.s, tc.o, ordering) 50 } else { 51 for i := range ordering { 52 if ordering[i] != tc.o[i] { 53 t.Errorf("%s: expected %s, actual: %s", tc.s, tc.o, ordering) 54 } 55 } 56 } 57 } 58 } 59 60 func TestOrderingChoice_ColSet(t *testing.T) { 61 testcases := []struct { 62 s string 63 cs opt.ColSet 64 }{ 65 {s: "", cs: opt.MakeColSet()}, 66 {s: "+1", cs: opt.MakeColSet(1)}, 67 {s: "-1,+(2|3) opt(4,5)", cs: opt.MakeColSet(1, 2, 3)}, 68 {s: "+(1|2),-(3|4),+5", cs: opt.MakeColSet(1, 2, 3, 4, 5)}, 69 } 70 71 for _, tc := range testcases { 72 choice := physical.ParseOrderingChoice(tc.s) 73 colSet := choice.ColSet() 74 if !colSet.Equals(tc.cs) { 75 t.Errorf("%s: expected %s, actual: %s", tc.s, tc.cs, colSet) 76 } 77 } 78 } 79 80 func TestOrderingChoice_Implies(t *testing.T) { 81 testcases := []struct { 82 left string 83 right string 84 expected bool 85 }{ 86 {left: "", right: "", expected: true}, 87 {left: "+1", right: "", expected: true}, 88 {left: "+1", right: "+1", expected: true}, 89 {left: "+1,-2", right: "+1", expected: true}, 90 {left: "+1,-2", right: "+1,-2", expected: true}, 91 {left: "+1", right: "+1 opt(2)", expected: true}, 92 {left: "-2,+1", right: "+1 opt(2)", expected: true}, 93 {left: "+1", right: "+(1|2)", expected: true}, 94 {left: "+(1|2)", right: "+(1|2|3)", expected: true}, 95 {left: "+(1|2),-4", right: "+(1|2|3),-(4|5)", expected: true}, 96 {left: "+(1|2) opt(4)", right: "+(1|2|3) opt(4)", expected: true}, 97 98 {left: "", right: "+1", expected: false}, 99 {left: "+1", right: "-1", expected: false}, 100 {left: "+1", right: "-1,-2", expected: false}, 101 {left: "+1 opt(2)", right: "+1", expected: false}, 102 {left: "+1 opt(2)", right: "+1 opt(3)", expected: false}, 103 {left: "+(1|2)", right: "-(1|2)", expected: false}, 104 {left: "+(1|2)", right: "+(3|4)", expected: false}, 105 {left: "+(1|2)", right: "+(2|3)", expected: false}, 106 {left: "+(1|2|3)", right: "+(1|2)", expected: false}, 107 {left: "+(1|2)", right: "+1 opt(2)", expected: false}, 108 {left: "+(1|2),-(3|4)", right: "+(1|2),-(3|4),+5", expected: false}, 109 {left: "+1", right: "+3 opt(1,2)", expected: false}, 110 {left: "+3 opt(1,2)", right: "+1", expected: false}, 111 } 112 113 for _, tc := range testcases { 114 left := physical.ParseOrderingChoice(tc.left) 115 right := physical.ParseOrderingChoice(tc.right) 116 if left.Implies(&right) != tc.expected { 117 if tc.expected { 118 t.Errorf("expected %s to imply %s", tc.left, tc.right) 119 } else { 120 t.Errorf("expected %s to not imply %s", tc.left, tc.right) 121 } 122 } 123 } 124 } 125 126 // TestOrderingChoice_Intersection tests Intersects and Intersection. 127 func TestOrderingChoice_Intersection(t *testing.T) { 128 testcases := []struct { 129 left string 130 right string 131 expected string 132 nonCommutative bool 133 }{ 134 {left: "", right: "", expected: ""}, 135 {left: "+1", right: "", expected: "+1"}, 136 {left: "+1 opt(2)", right: "", expected: "+1 opt(2)"}, 137 {left: "+1", right: "+1", expected: "+1"}, 138 {left: "+1,-2", right: "+1", expected: "+1,-2"}, 139 {left: "+1,-2", right: "+1,-2", expected: "+1,-2"}, 140 {left: "+1", right: "+1 opt(2)", expected: "+1"}, 141 {left: "+1", right: "+2 opt(1)", expected: "+1,+2"}, 142 {left: "-2,+1", right: "+1 opt(2)", expected: "-2,+1"}, 143 {left: "+1", right: "+(1|2)", expected: "+1"}, 144 {left: "+(1|2)", right: "+(1|2|3)", expected: "+(1|2)"}, 145 {left: "+(1|2),-4", right: "+(1|2|3),-(4|5)", expected: "+(1|2),-4"}, 146 {left: "+(1|2) opt(4)", right: "+(1|2|3) opt(4)", expected: "+(1|2) opt(4)"}, 147 148 {left: "+1 opt(2,3,4)", right: "+1 opt(4,5)", expected: "+1 opt(4)"}, 149 {left: "+1 opt(2,3,4)", right: "+1 opt(4,5)", expected: "+1 opt(4)"}, 150 {left: "+1,+4,+5", right: "+4,+5 opt(1)", expected: "+1,+4,+5"}, 151 {left: "+(1|2),+(3|4)", right: "+(2|3),+(4|5)", expected: "+2,+4"}, 152 {left: "+(1|2|3),+(4|5)", right: "+(2|3),+(4|5|6)", expected: "+(2|3),+(4|5)"}, 153 154 {left: "+1", right: "+2", expected: "NO"}, 155 {left: "+1", right: "+2 opt(2)", expected: "NO"}, 156 {left: "+1", right: "-1 opt(2)", expected: "NO"}, 157 {left: "+(1|2),+(3|4)", right: "+(2|5),+(6|7)", expected: "NO"}, 158 159 // Non-commutative cases. 160 { 161 left: "+1 opt(2,5)", 162 right: "+2 opt(1,5)", 163 expected: "+1,+2 opt(5)", 164 nonCommutative: true, 165 }, 166 { 167 left: "+2 opt(1,5)", 168 right: "+1 opt(2,5)", 169 expected: "+2,+1 opt(5)", 170 nonCommutative: true, 171 }, 172 { 173 left: "+(1|2),+(3|4) opt(6)", 174 right: "+(2|3),+(5|6) opt(4)", 175 expected: "+2,+4,+(5|6)", 176 nonCommutative: true, 177 }, 178 { 179 left: "+(2|3),+(5|6) opt(4)", 180 right: "+(1|2),+(3|4) opt(6)", 181 expected: "+2,+6,+(3|4)", 182 nonCommutative: true, 183 }, 184 { 185 left: "+(1|2|3),-(4|5|6) opt(7)", 186 right: "-7 opt(2,3,5,6)", 187 expected: "+(2|3),-(5|6),-7", 188 nonCommutative: true, 189 }, 190 { 191 left: "-7 opt(2,3,5,6)", 192 right: "+(1|2|3),-(4|5|6) opt(7)", 193 expected: "-7,+(1|2|3),-(4|5|6)", 194 nonCommutative: true, 195 }, 196 } 197 198 getRes := func(left, right physical.OrderingChoice) string { 199 if !left.Intersects(&right) { 200 return "NO" 201 } 202 return left.Intersection(&right).String() 203 } 204 205 for _, tc := range testcases { 206 left := physical.ParseOrderingChoice(tc.left) 207 right := physical.ParseOrderingChoice(tc.right) 208 209 res := getRes(left, right) 210 if res != tc.expected { 211 t.Errorf( 212 "intersection between '%s' and '%s': expected '%s', got '%s'", 213 left, right, tc.expected, res, 214 ) 215 } 216 if !tc.nonCommutative { 217 if res2 := getRes(right, left); res2 != res { 218 t.Errorf( 219 "intersection not commutative: left='%s' right='%s': '%s' vs '%s'", 220 left, right, res, res2, 221 ) 222 } 223 } 224 } 225 } 226 227 func TestOrderingChoice_SubsetOfCols(t *testing.T) { 228 testcases := []struct { 229 s string 230 cs opt.ColSet 231 expected bool 232 }{ 233 {s: "", cs: opt.MakeColSet(), expected: true}, 234 {s: "", cs: opt.MakeColSet(1), expected: true}, 235 {s: "+1", cs: opt.MakeColSet(1), expected: true}, 236 {s: "-1", cs: opt.MakeColSet(1, 2), expected: true}, 237 {s: "+1 opt(2)", cs: opt.MakeColSet(1), expected: false}, 238 {s: "+1 opt(2)", cs: opt.MakeColSet(1, 2), expected: true}, 239 {s: "+(1|2)", cs: opt.MakeColSet(1, 2, 3), expected: true}, 240 {s: "+(1|2)", cs: opt.MakeColSet(2), expected: false}, 241 {s: "+1,-(2|3),-4 opt(4,5)", cs: opt.MakeColSet(1, 3, 4), expected: false}, 242 {s: "+1,-(2|3),-4 opt(4,5)", cs: opt.MakeColSet(1, 2, 3, 4), expected: false}, 243 {s: "+1,-(2|3),-4 opt(4,5)", cs: opt.MakeColSet(1, 2, 3, 4, 5), expected: true}, 244 } 245 246 for _, tc := range testcases { 247 choice := physical.ParseOrderingChoice(tc.s) 248 if choice.SubsetOfCols(tc.cs) != tc.expected { 249 if tc.expected { 250 t.Errorf("%s: expected cols to be subset of %s", tc.s, tc.cs) 251 } else { 252 t.Errorf("%s: expected cols to not be subset of %s", tc.s, tc.cs) 253 } 254 } 255 } 256 } 257 258 func TestOrderingChoice_CanProjectCols(t *testing.T) { 259 testcases := []struct { 260 s string 261 cs opt.ColSet 262 expected bool 263 }{ 264 {s: "", cs: opt.MakeColSet(), expected: true}, 265 {s: "", cs: opt.MakeColSet(1), expected: true}, 266 {s: "+1", cs: opt.MakeColSet(1), expected: true}, 267 {s: "-1", cs: opt.MakeColSet(1, 2), expected: true}, 268 {s: "+1 opt(2)", cs: opt.MakeColSet(1), expected: true}, 269 {s: "+(1|2)", cs: opt.MakeColSet(1), expected: true}, 270 {s: "+(1|2)", cs: opt.MakeColSet(2), expected: true}, 271 {s: "+1,-(2|3),-4 opt(4,5)", cs: opt.MakeColSet(1, 3, 4), expected: true}, 272 273 {s: "+1", cs: opt.MakeColSet(), expected: false}, 274 {s: "+1,+2", cs: opt.MakeColSet(1), expected: false}, 275 {s: "+(1|2)", cs: opt.MakeColSet(3), expected: false}, 276 } 277 278 for _, tc := range testcases { 279 choice := physical.ParseOrderingChoice(tc.s) 280 if choice.CanProjectCols(tc.cs) != tc.expected { 281 if tc.expected { 282 t.Errorf("%s: expected CanProject(%s)", tc.s, tc.cs) 283 } else { 284 t.Errorf("%s: expected !CanProject(%s)", tc.s, tc.cs) 285 } 286 } 287 } 288 } 289 290 func TestOrderingChoice_MatchesAt(t *testing.T) { 291 s1 := "+1" 292 s2 := "+1,-2 opt(3,4)" 293 s3 := "+(1|2)" 294 s4 := "+(1|2),-3,+(4|5) opt(6,7)" 295 296 testcases := []struct { 297 s string 298 idx int 299 col opt.ColumnID 300 desc bool 301 expected bool 302 }{ 303 {s: s1, idx: 0, col: 1, desc: false, expected: true}, 304 {s: s1, idx: 0, col: 1, desc: true, expected: false}, 305 {s: s1, idx: 0, col: 2, desc: false, expected: false}, 306 307 {s: s2, idx: 0, col: 1, desc: false, expected: true}, 308 {s: s2, idx: 1, col: 2, desc: true, expected: true}, 309 {s: s2, idx: 1, col: 2, desc: false, expected: false}, 310 {s: s2, idx: 1, col: 3, desc: false, expected: true}, 311 {s: s2, idx: 0, col: 4, desc: false, expected: true}, 312 313 {s: s3, idx: 0, col: 1, desc: false, expected: true}, 314 {s: s3, idx: 0, col: 2, desc: false, expected: true}, 315 {s: s3, idx: 0, col: 2, desc: true, expected: false}, 316 {s: s3, idx: 0, col: 3, desc: false, expected: false}, 317 318 {s: s4, idx: 0, col: 6, desc: false, expected: true}, 319 {s: s4, idx: 1, col: 3, desc: true, expected: true}, 320 {s: s4, idx: 2, col: 5, desc: false, expected: true}, 321 {s: s4, idx: 2, col: 7, desc: true, expected: true}, 322 } 323 324 for _, tc := range testcases { 325 ordering := physical.ParseOrderingChoice(tc.s) 326 ordCol := opt.MakeOrderingColumn(tc.col, tc.desc) 327 if ordering.MatchesAt(tc.idx, ordCol) != tc.expected { 328 if tc.expected { 329 t.Errorf("expected %s to match at index %d: %s", ordCol, tc.idx, tc.s) 330 } else { 331 t.Errorf("expected %s not to match at index %d: %s", ordCol, tc.idx, tc.s) 332 } 333 } 334 } 335 } 336 337 func TestOrderingChoice_Copy(t *testing.T) { 338 ordering := physical.ParseOrderingChoice("+1,-(2|3) opt(4,5)") 339 copied := ordering.Copy() 340 col := physical.OrderingColumnChoice{Group: opt.MakeColSet(6, 7), Descending: true} 341 copied.Columns = append(copied.Columns, col) 342 343 // ()-->(8) 344 // (3)==(9) 345 // (9)==(3) 346 var fd props.FuncDepSet 347 fd.AddConstants(opt.MakeColSet(8)) 348 fd.AddEquivalency(3, 9) 349 copied.Simplify(&fd) 350 351 if ordering.String() != "+1,-(2|3) opt(4,5)" { 352 t.Errorf("original was modified: %s", ordering.String()) 353 } 354 355 if copied.String() != "+1,-(2|3|9),-(6|7) opt(4,5,8)" { 356 t.Errorf("copy is not correct: %s", copied.String()) 357 } 358 } 359 360 func TestOrderingChoice_Simplify(t *testing.T) { 361 // ()-->(4,5) 362 // (1)==(1,3) 363 // (2)==(1) 364 // (3)==(1) 365 var fd1 props.FuncDepSet 366 fd1.AddConstants(opt.MakeColSet(4, 5)) 367 fd1.AddEquivalency(1, 2) 368 fd1.AddEquivalency(1, 3) 369 370 // (1)-->(1,2,3,4,5) 371 // (2)-->(4) 372 // (4)-->(5) 373 // (2)==(3) 374 // (3)==(2) 375 var fd2 props.FuncDepSet 376 fd2.AddStrictKey(opt.MakeColSet(1), opt.MakeColSet(1, 2, 3, 4, 5)) 377 fd2.AddSynthesizedCol(opt.MakeColSet(2), 4) 378 fd2.AddSynthesizedCol(opt.MakeColSet(4), 5) 379 fd2.AddEquivalency(2, 3) 380 381 testcases := []struct { 382 fdset *props.FuncDepSet 383 s string 384 expected string 385 }{ 386 {fdset: &props.FuncDepSet{}, s: "", expected: ""}, 387 388 // Constants and equivalencies. 389 {fdset: &fd1, s: "", expected: ""}, 390 {fdset: &fd1, s: "+1,+4", expected: "+(1|2|3) opt(4,5)"}, 391 {fdset: &fd1, s: "+2,+4", expected: "+(1|2|3) opt(4,5)"}, 392 {fdset: &fd1, s: "+1,+2 opt(4)", expected: "+(1|2|3) opt(4,5)"}, 393 {fdset: &fd1, s: "+1,+2 opt(4)", expected: "+(1|2|3) opt(4,5)"}, 394 {fdset: &fd1, s: "+(4|5)", expected: ""}, 395 {fdset: &fd1, s: "+(4|5) opt(3)", expected: ""}, 396 {fdset: &fd1, s: "+(4|5|6)", expected: "+6 opt(4,5)"}, 397 {fdset: &fd1, s: "+(4|6)", expected: "+6 opt(4,5)"}, 398 399 // Columns functionally determine one another. 400 {fdset: &fd2, s: "", expected: ""}, 401 {fdset: &fd2, s: "+1,+2,+4", expected: "+1"}, 402 {fdset: &fd2, s: "+2,+4,+5", expected: "+(2|3)"}, 403 {fdset: &fd2, s: "+3,+5", expected: "+(2|3)"}, 404 {fdset: &fd2, s: "-(2|3),+1,+5", expected: "-(2|3),+1"}, 405 {fdset: &fd2, s: "-(2|4),+5,+1", expected: "-(2|3|4),+1"}, 406 } 407 408 for _, tc := range testcases { 409 ordering := physical.ParseOrderingChoice(tc.s) 410 411 if ordering.String() != tc.expected && !ordering.CanSimplify(tc.fdset) { 412 t.Errorf("%s: expected CanSimplify to be true", tc.s) 413 } 414 415 ordering.Simplify(tc.fdset) 416 if ordering.String() != tc.expected { 417 t.Errorf("%s: expected %s, actual %s", tc.s, tc.expected, ordering.String()) 418 } 419 420 if ordering.CanSimplify(tc.fdset) { 421 t.Errorf("%s: expected CanSimplify to be false", ordering.String()) 422 } 423 } 424 } 425 426 func TestOrderingChoice_Truncate(t *testing.T) { 427 testcases := []struct { 428 s string 429 n int 430 expected string 431 }{ 432 {s: "", n: 0, expected: ""}, 433 {s: "", n: 1, expected: ""}, 434 {s: "+1,+(2|3),-4 opt(5,6)", n: 0, expected: ""}, 435 {s: "+1,+(2|3),-4 opt(5,6)", n: 1, expected: "+1 opt(5,6)"}, 436 {s: "+1,+(2|3),-4 opt(5,6)", n: 2, expected: "+1,+(2|3) opt(5,6)"}, 437 {s: "+1,+(2|3),-4 opt(5,6)", n: 3, expected: "+1,+(2|3),-4 opt(5,6)"}, 438 {s: "+1,+(2|3),-4 opt(5,6)", n: 4, expected: "+1,+(2|3),-4 opt(5,6)"}, 439 } 440 441 for _, tc := range testcases { 442 choice := physical.ParseOrderingChoice(tc.s) 443 choice.Truncate(tc.n) 444 if choice.String() != tc.expected { 445 t.Errorf("%s: n=%d, expected: %s, actual: %s", tc.s, tc.n, tc.expected, choice.String()) 446 } 447 } 448 } 449 450 func TestOrderingChoice_ProjectCols(t *testing.T) { 451 testcases := []struct { 452 s string 453 cols []opt.ColumnID 454 expected string 455 }{ 456 {s: "", cols: []opt.ColumnID{}, expected: ""}, 457 {s: "+1,+(2|3),-4 opt(5,6)", cols: []opt.ColumnID{1, 2, 3, 4, 5, 6}, expected: "+1,+(2|3),-4 opt(5,6)"}, 458 {s: "+1,+(2|3),-4 opt(5,6)", cols: []opt.ColumnID{1, 2, 4, 5, 6}, expected: "+1,+2,-4 opt(5,6)"}, 459 {s: "+1,+(2|3),-4 opt(5,6)", cols: []opt.ColumnID{1, 3, 4, 5, 6}, expected: "+1,+3,-4 opt(5,6)"}, 460 {s: "+1,+(2|3),-4 opt(5,6)", cols: []opt.ColumnID{1, 2, 4, 5}, expected: "+1,+2,-4 opt(5)"}, 461 {s: "+1,+(2|3),-4 opt(5,6)", cols: []opt.ColumnID{1, 2, 4}, expected: "+1,+2,-4"}, 462 } 463 464 for _, tc := range testcases { 465 choice := physical.ParseOrderingChoice(tc.s) 466 choice.ProjectCols(opt.MakeColSet(tc.cols...)) 467 if choice.String() != tc.expected { 468 t.Errorf("%s: cols=%v, expected: %s, actual: %s", tc.s, tc.cols, tc.expected, choice.String()) 469 } 470 } 471 } 472 473 func TestOrderingChoice_Equals(t *testing.T) { 474 testcases := []struct { 475 left string 476 right string 477 expected bool 478 }{ 479 {left: "", right: "", expected: true}, 480 {left: "+1", right: "+1", expected: true}, 481 {left: "+1,+2", right: "+1,+2", expected: true}, 482 {left: "+(1|2)", right: "+(2|1)", expected: true}, 483 {left: "+(1|2),+3", right: "+(2|1),+3", expected: true}, 484 {left: "+(1|2),-(3|4) opt(5,6)", right: "+(2|1),-(4|3) opt(6,5)", expected: true}, 485 486 {left: "+1", right: "", expected: false}, 487 {left: "+1", right: "-1", expected: false}, 488 {left: "+1", right: "+2", expected: false}, 489 {left: "+1,+2", right: "+2,+1", expected: false}, 490 {left: "+1 opt(2)", right: "+1 opt(2,3)", expected: false}, 491 } 492 493 for _, tc := range testcases { 494 left := physical.ParseOrderingChoice(tc.left) 495 right := physical.ParseOrderingChoice(tc.right) 496 if left.Equals(&right) != tc.expected { 497 if tc.expected { 498 t.Errorf("expected %s to equal %s", tc.left, tc.right) 499 } else { 500 t.Errorf("expected %s to not equal %s", tc.left, tc.right) 501 } 502 } 503 } 504 } 505 506 func TestOrderingChoice_PrefixIntersection(t *testing.T) { 507 testcases := []struct { 508 x string 509 prefix opt.ColList 510 y string 511 expected string 512 }{ 513 {x: "+1", prefix: opt.ColList{}, y: "+2", expected: "fail"}, 514 {x: "", prefix: opt.ColList{}, y: "+1", expected: "+1"}, 515 {x: "", prefix: opt.ColList{}, y: "+1,+2", expected: "+1,+2"}, 516 {x: "+(1|2)", prefix: opt.ColList{}, y: "+(1|2)", expected: "+(1|2)"}, 517 {x: "+(1|2)", prefix: opt.ColList{}, y: "+1", expected: "+1"}, 518 {x: "+(1|2)", prefix: opt.ColList{}, y: "+2", expected: "+2"}, 519 {x: "+1,+2", prefix: opt.ColList{3}, y: "", expected: "fail"}, 520 {x: "", prefix: opt.ColList{3}, y: "+1,+2", expected: "+3,+1,+2"}, 521 {x: "+1,+2", prefix: opt.ColList{3, 4}, y: "", expected: "fail"}, 522 {x: "", prefix: opt.ColList{3, 4}, y: "+1,+2", expected: "+3,+4,+1,+2"}, 523 {x: "+1", prefix: opt.ColList{}, y: "+1", expected: "+1"}, 524 {x: "+1,+2", prefix: opt.ColList{}, y: "+1", expected: "+1,+2"}, 525 {x: "+1", prefix: opt.ColList{}, y: "+1,+2", expected: "+1,+2"}, 526 {x: "+1,+2", prefix: opt.ColList{}, y: "+1,+2", expected: "+1,+2"}, 527 {x: "+1,+2", prefix: opt.ColList{1}, y: "+2", expected: "+1,+2"}, 528 {x: "+2", prefix: opt.ColList{3}, y: "+1,+2", expected: "fail"}, 529 {x: "+1,+2", prefix: opt.ColList{}, y: "+1,+2", expected: "+1,+2"}, 530 {x: "+1,+2", prefix: opt.ColList{1}, y: "+2,+3", expected: "+1,+2,+3"}, 531 {x: "+1,+2", prefix: opt.ColList{1, 2}, y: "+3", expected: "+1,+2,+3"}, 532 {x: "+1,+2", prefix: opt.ColList{1, 2}, y: "", expected: "+1,+2"}, 533 {x: "+2,+1", prefix: opt.ColList{1, 2}, y: "", expected: "+2,+1"}, 534 {x: "+2,+3", prefix: opt.ColList{3}, y: "+1,+2", expected: "fail"}, 535 {x: "", prefix: opt.ColList{1, 2}, y: "", expected: "+1,+2"}, 536 {x: "", prefix: opt.ColList{2}, y: "+3 opt(2)", expected: "+2,+3"}, 537 {x: "", prefix: opt.ColList{2}, y: "+3", expected: "+2,+3"}, 538 } 539 540 for _, tc := range testcases { 541 left := physical.ParseOrderingChoice(tc.x) 542 right := physical.ParseOrderingChoice(tc.y) 543 544 cols := tc.prefix.ToSet() 545 546 result, ok := left.PrefixIntersection(cols, right.Columns) 547 s := "fail" 548 if ok { 549 s = result.String() 550 } 551 552 if s != tc.expected { 553 t.Errorf("%q.PrefixIntersection(%q, %q): expected %q, got %q", left, cols, right, tc.expected, s) 554 } 555 } 556 }