github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/colexec/mergejoiner_test.go (about) 1 // Copyright 2019 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 colexec 12 13 import ( 14 "context" 15 "fmt" 16 "testing" 17 18 "github.com/cockroachdb/cockroach/pkg/col/coldata" 19 "github.com/cockroachdb/cockroach/pkg/col/coldatatestutils" 20 "github.com/cockroachdb/cockroach/pkg/settings/cluster" 21 "github.com/cockroachdb/cockroach/pkg/sql/colexecbase" 22 "github.com/cockroachdb/cockroach/pkg/sql/colmem" 23 "github.com/cockroachdb/cockroach/pkg/sql/execinfra" 24 "github.com/cockroachdb/cockroach/pkg/sql/execinfrapb" 25 "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" 26 "github.com/cockroachdb/cockroach/pkg/sql/sqlbase" 27 "github.com/cockroachdb/cockroach/pkg/sql/types" 28 "github.com/cockroachdb/cockroach/pkg/testutils/colcontainerutils" 29 "github.com/cockroachdb/cockroach/pkg/util/humanizeutil" 30 "github.com/cockroachdb/cockroach/pkg/util/leaktest" 31 "github.com/cockroachdb/cockroach/pkg/util/mon" 32 "github.com/cockroachdb/cockroach/pkg/util/randutil" 33 "github.com/stretchr/testify/require" 34 ) 35 36 func createSpecForMergeJoiner(tc *joinTestCase) *execinfrapb.ProcessorSpec { 37 leftOrdering := execinfrapb.Ordering{} 38 for i, eqCol := range tc.leftEqCols { 39 leftOrdering.Columns = append( 40 leftOrdering.Columns, 41 execinfrapb.Ordering_Column{ 42 ColIdx: eqCol, 43 Direction: tc.leftDirections[i], 44 }, 45 ) 46 } 47 rightOrdering := execinfrapb.Ordering{} 48 for i, eqCol := range tc.rightEqCols { 49 rightOrdering.Columns = append( 50 rightOrdering.Columns, 51 execinfrapb.Ordering_Column{ 52 ColIdx: eqCol, 53 Direction: tc.rightDirections[i], 54 }, 55 ) 56 } 57 mjSpec := &execinfrapb.MergeJoinerSpec{ 58 LeftOrdering: leftOrdering, 59 RightOrdering: rightOrdering, 60 OnExpr: tc.onExpr, 61 Type: tc.joinType, 62 } 63 projection := make([]uint32, 0, len(tc.leftOutCols)+len(tc.rightOutCols)) 64 projection = append(projection, tc.leftOutCols...) 65 rColOffset := uint32(len(tc.leftTypes)) 66 for _, outCol := range tc.rightOutCols { 67 projection = append(projection, rColOffset+outCol) 68 } 69 return &execinfrapb.ProcessorSpec{ 70 Input: []execinfrapb.InputSyncSpec{ 71 {ColumnTypes: tc.leftTypes}, 72 {ColumnTypes: tc.rightTypes}, 73 }, 74 Core: execinfrapb.ProcessorCoreUnion{ 75 MergeJoiner: mjSpec, 76 }, 77 Post: execinfrapb.PostProcessSpec{ 78 Projection: true, 79 OutputColumns: projection, 80 }, 81 } 82 } 83 84 var mjTestCases = []*joinTestCase{ 85 { 86 description: "basic test", 87 leftTypes: []*types.T{types.Int}, 88 rightTypes: []*types.T{types.Int}, 89 leftTuples: tuples{{1}, {2}, {3}, {4}}, 90 rightTuples: tuples{{1}, {2}, {3}, {4}}, 91 leftOutCols: []uint32{0}, 92 rightOutCols: []uint32{}, 93 leftEqCols: []uint32{0}, 94 rightEqCols: []uint32{0}, 95 expected: tuples{{1}, {2}, {3}, {4}}, 96 }, 97 { 98 description: "basic test, no out cols", 99 leftTypes: []*types.T{types.Int}, 100 rightTypes: []*types.T{types.Int}, 101 leftTuples: tuples{{1}, {2}, {3}, {4}}, 102 rightTuples: tuples{{1}, {2}, {3}, {4}}, 103 leftOutCols: []uint32{}, 104 rightOutCols: []uint32{}, 105 leftEqCols: []uint32{0}, 106 rightEqCols: []uint32{0}, 107 expected: tuples{{}, {}, {}, {}}, 108 }, 109 { 110 description: "basic test, out col on left", 111 leftTypes: []*types.T{types.Int}, 112 rightTypes: []*types.T{types.Int}, 113 leftTuples: tuples{{1}, {2}, {3}, {4}}, 114 rightTuples: tuples{{1}, {2}, {3}, {4}}, 115 leftOutCols: []uint32{0}, 116 rightOutCols: []uint32{}, 117 leftEqCols: []uint32{0}, 118 rightEqCols: []uint32{0}, 119 expected: tuples{{1}, {2}, {3}, {4}}, 120 }, 121 { 122 description: "basic test, out col on right", 123 leftTypes: []*types.T{types.Int}, 124 rightTypes: []*types.T{types.Int}, 125 leftTuples: tuples{{1}, {2}, {3}, {4}}, 126 rightTuples: tuples{{1}, {2}, {3}, {4}}, 127 leftOutCols: []uint32{}, 128 rightOutCols: []uint32{0}, 129 leftEqCols: []uint32{0}, 130 rightEqCols: []uint32{0}, 131 expected: tuples{{1}, {2}, {3}, {4}}, 132 }, 133 { 134 description: "basic test, L missing", 135 leftTypes: []*types.T{types.Int}, 136 rightTypes: []*types.T{types.Int}, 137 leftTuples: tuples{{1}, {3}, {4}}, 138 rightTuples: tuples{{1}, {2}, {3}, {4}}, 139 leftOutCols: []uint32{0}, 140 rightOutCols: []uint32{}, 141 leftEqCols: []uint32{0}, 142 rightEqCols: []uint32{0}, 143 expected: tuples{{1}, {3}, {4}}, 144 }, 145 { 146 description: "basic test, R missing", 147 leftTypes: []*types.T{types.Int}, 148 rightTypes: []*types.T{types.Int}, 149 leftTuples: tuples{{1}, {2}, {3}, {4}}, 150 rightTuples: tuples{{1}, {3}, {4}}, 151 leftOutCols: []uint32{}, 152 rightOutCols: []uint32{0}, 153 leftEqCols: []uint32{0}, 154 rightEqCols: []uint32{0}, 155 expected: tuples{{1}, {3}, {4}}, 156 }, 157 { 158 description: "basic test, L duplicate", 159 leftTypes: []*types.T{types.Int}, 160 rightTypes: []*types.T{types.Int}, 161 leftTuples: tuples{{1}, {1}, {2}, {3}, {4}}, 162 rightTuples: tuples{{1}, {2}, {3}, {4}}, 163 leftOutCols: []uint32{0}, 164 rightOutCols: []uint32{}, 165 leftEqCols: []uint32{0}, 166 rightEqCols: []uint32{0}, 167 expected: tuples{{1}, {1}, {2}, {3}, {4}}, 168 }, 169 { 170 description: "basic test, R duplicate", 171 leftTypes: []*types.T{types.Int}, 172 rightTypes: []*types.T{types.Int}, 173 leftTuples: tuples{{1}, {2}, {3}, {4}}, 174 rightTuples: tuples{{1}, {1}, {2}, {3}, {4}}, 175 leftOutCols: []uint32{}, 176 rightOutCols: []uint32{0}, 177 leftEqCols: []uint32{0}, 178 rightEqCols: []uint32{0}, 179 expected: tuples{{1}, {1}, {2}, {3}, {4}}, 180 }, 181 { 182 description: "basic test, R duplicate 2", 183 leftTypes: []*types.T{types.Int}, 184 rightTypes: []*types.T{types.Int}, 185 leftTuples: tuples{{1}, {2}}, 186 rightTuples: tuples{{1}, {1}, {2}}, 187 leftOutCols: []uint32{0}, 188 rightOutCols: []uint32{}, 189 leftEqCols: []uint32{0}, 190 rightEqCols: []uint32{0}, 191 expected: tuples{{1}, {1}, {2}}, 192 }, 193 { 194 description: "basic test, L+R duplicates", 195 leftTypes: []*types.T{types.Int}, 196 rightTypes: []*types.T{types.Int}, 197 leftTuples: tuples{{1}, {1}, {2}, {3}, {4}}, 198 rightTuples: tuples{{1}, {1}, {2}, {3}, {4}}, 199 leftOutCols: []uint32{}, 200 rightOutCols: []uint32{0}, 201 leftEqCols: []uint32{0}, 202 rightEqCols: []uint32{0}, 203 expected: tuples{{1}, {1}, {1}, {1}, {2}, {3}, {4}}, 204 }, 205 { 206 description: "basic test, L+R duplicate, multiple runs", 207 leftTypes: []*types.T{types.Int}, 208 rightTypes: []*types.T{types.Int}, 209 leftTuples: tuples{{1}, {2}, {2}, {2}, {3}, {4}}, 210 rightTuples: tuples{{1}, {1}, {2}, {3}, {4}}, 211 leftOutCols: []uint32{}, 212 rightOutCols: []uint32{0}, 213 leftEqCols: []uint32{0}, 214 rightEqCols: []uint32{0}, 215 expected: tuples{{1}, {1}, {2}, {2}, {2}, {3}, {4}}, 216 }, 217 { 218 description: "cross product test, batch size = col.BatchSize()", 219 leftTypes: []*types.T{types.Int}, 220 rightTypes: []*types.T{types.Int}, 221 leftTuples: tuples{{1}, {1}, {1}, {1}}, 222 rightTuples: tuples{{1}, {1}, {1}, {1}}, 223 leftOutCols: []uint32{0}, 224 rightOutCols: []uint32{}, 225 leftEqCols: []uint32{0}, 226 rightEqCols: []uint32{0}, 227 expected: tuples{{1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}}, 228 }, 229 { 230 description: "cross product test, batch size = 4 (small even)", 231 leftTypes: []*types.T{types.Int}, 232 rightTypes: []*types.T{types.Int}, 233 leftTuples: tuples{{1}, {1}, {1}, {1}}, 234 rightTuples: tuples{{1}, {1}, {1}, {1}}, 235 leftOutCols: []uint32{0}, 236 rightOutCols: []uint32{}, 237 leftEqCols: []uint32{0}, 238 rightEqCols: []uint32{0}, 239 expected: tuples{{1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}}, 240 outputBatchSize: 4, 241 }, 242 { 243 description: "cross product test, batch size = 3 (small odd)", 244 leftTypes: []*types.T{types.Int}, 245 rightTypes: []*types.T{types.Int}, 246 leftTuples: tuples{{1}, {1}, {1}, {1}}, 247 rightTuples: tuples{{1}, {1}, {1}, {1}}, 248 leftOutCols: []uint32{}, 249 rightOutCols: []uint32{0}, 250 leftEqCols: []uint32{0}, 251 rightEqCols: []uint32{0}, 252 expected: tuples{{1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}}, 253 outputBatchSize: 3, 254 }, 255 { 256 description: "cross product test, batch size = 1 (unit)", 257 leftTypes: []*types.T{types.Int}, 258 rightTypes: []*types.T{types.Int}, 259 leftTuples: tuples{{1}, {1}, {1}, {1}}, 260 rightTuples: tuples{{1}, {1}, {1}, {1}}, 261 leftOutCols: []uint32{}, 262 rightOutCols: []uint32{0}, 263 leftEqCols: []uint32{0}, 264 rightEqCols: []uint32{0}, 265 expected: tuples{{1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}}, 266 outputBatchSize: 1, 267 }, 268 { 269 description: "multi output column test, basic", 270 leftTypes: []*types.T{types.Int, types.Int}, 271 rightTypes: []*types.T{types.Int, types.Int}, 272 leftTuples: tuples{{1, 10}, {2, 20}, {3, 30}, {4, 40}}, 273 rightTuples: tuples{{1, 11}, {2, 12}, {3, 13}, {4, 14}}, 274 leftOutCols: []uint32{0, 1}, 275 rightOutCols: []uint32{0, 1}, 276 leftEqCols: []uint32{0}, 277 rightEqCols: []uint32{0}, 278 expected: tuples{{1, 10, 1, 11}, {2, 20, 2, 12}, {3, 30, 3, 13}, {4, 40, 4, 14}}, 279 }, 280 { 281 description: "multi output column test, batch size = 1", 282 leftTypes: []*types.T{types.Int, types.Int}, 283 rightTypes: []*types.T{types.Int, types.Int}, 284 leftTuples: tuples{{1, 10}, {2, 20}, {3, 30}, {4, 40}}, 285 rightTuples: tuples{{1, 11}, {2, 12}, {3, 13}, {4, 14}}, 286 leftOutCols: []uint32{0, 1}, 287 rightOutCols: []uint32{0, 1}, 288 leftEqCols: []uint32{0}, 289 rightEqCols: []uint32{0}, 290 expected: tuples{{1, 10, 1, 11}, {2, 20, 2, 12}, {3, 30, 3, 13}, {4, 40, 4, 14}}, 291 outputBatchSize: 1, 292 }, 293 { 294 description: "multi output column test, test output coldata projection", 295 leftTypes: []*types.T{types.Int, types.Int}, 296 rightTypes: []*types.T{types.Int, types.Int}, 297 leftTuples: tuples{{1, 10}, {2, 20}, {3, 30}, {4, 40}}, 298 rightTuples: tuples{{1, 11}, {2, 12}, {3, 13}, {4, 14}}, 299 leftOutCols: []uint32{0}, 300 rightOutCols: []uint32{0}, 301 leftEqCols: []uint32{0}, 302 rightEqCols: []uint32{0}, 303 expected: tuples{{1, 1}, {2, 2}, {3, 3}, {4, 4}}, 304 }, 305 { 306 description: "multi output column test, test output coldata projection", 307 leftTypes: []*types.T{types.Int, types.Int}, 308 rightTypes: []*types.T{types.Int, types.Int}, 309 leftTuples: tuples{{1, 10}, {2, 20}, {3, 30}, {4, 40}}, 310 rightTuples: tuples{{1, 11}, {2, 12}, {3, 13}, {4, 14}}, 311 leftOutCols: []uint32{1}, 312 rightOutCols: []uint32{1}, 313 leftEqCols: []uint32{0}, 314 rightEqCols: []uint32{0}, 315 expected: tuples{{10, 11}, {20, 12}, {30, 13}, {40, 14}}, 316 }, 317 { 318 description: "multi output column test, L run", 319 leftTypes: []*types.T{types.Int, types.Int}, 320 rightTypes: []*types.T{types.Int, types.Int}, 321 leftTuples: tuples{{1, 10}, {2, 20}, {2, 21}, {3, 30}, {4, 40}}, 322 rightTuples: tuples{{1, 11}, {2, 12}, {3, 13}, {4, 14}}, 323 leftOutCols: []uint32{0, 1}, 324 rightOutCols: []uint32{0, 1}, 325 leftEqCols: []uint32{0}, 326 rightEqCols: []uint32{0}, 327 expected: tuples{{1, 10, 1, 11}, {2, 20, 2, 12}, {2, 21, 2, 12}, {3, 30, 3, 13}, {4, 40, 4, 14}}, 328 }, 329 { 330 description: "multi output column test, L run, batch size = 1", 331 leftTypes: []*types.T{types.Int, types.Int}, 332 rightTypes: []*types.T{types.Int, types.Int}, 333 leftTuples: tuples{{1, 10}, {2, 20}, {2, 21}, {3, 30}, {4, 40}}, 334 rightTuples: tuples{{1, 11}, {2, 12}, {3, 13}, {4, 14}}, 335 leftOutCols: []uint32{0, 1}, 336 rightOutCols: []uint32{0, 1}, 337 leftEqCols: []uint32{0}, 338 rightEqCols: []uint32{0}, 339 expected: tuples{{1, 10, 1, 11}, {2, 20, 2, 12}, {2, 21, 2, 12}, {3, 30, 3, 13}, {4, 40, 4, 14}}, 340 outputBatchSize: 1, 341 }, 342 { 343 description: "multi output column test, R run", 344 leftTypes: []*types.T{types.Int, types.Int}, 345 rightTypes: []*types.T{types.Int, types.Int}, 346 leftTuples: tuples{{1, 10}, {2, 20}, {3, 30}, {4, 40}}, 347 rightTuples: tuples{{1, 11}, {1, 111}, {2, 12}, {3, 13}, {4, 14}}, 348 leftOutCols: []uint32{0, 1}, 349 rightOutCols: []uint32{0, 1}, 350 leftEqCols: []uint32{0}, 351 rightEqCols: []uint32{0}, 352 expected: tuples{{1, 10, 1, 11}, {1, 10, 1, 111}, {2, 20, 2, 12}, {3, 30, 3, 13}, {4, 40, 4, 14}}, 353 }, 354 { 355 description: "multi output column test, R run, batch size = 1", 356 leftTypes: []*types.T{types.Int, types.Int}, 357 rightTypes: []*types.T{types.Int, types.Int}, 358 leftTuples: tuples{{1, 10}, {2, 20}, {3, 30}, {4, 40}}, 359 rightTuples: tuples{{1, 11}, {1, 111}, {2, 12}, {3, 13}, {4, 14}}, 360 leftOutCols: []uint32{0, 1}, 361 rightOutCols: []uint32{0, 1}, 362 leftEqCols: []uint32{0}, 363 rightEqCols: []uint32{0}, 364 expected: tuples{{1, 10, 1, 11}, {1, 10, 1, 111}, {2, 20, 2, 12}, {3, 30, 3, 13}, {4, 40, 4, 14}}, 365 outputBatchSize: 1, 366 }, 367 { 368 description: "logic test", 369 leftTypes: []*types.T{types.Int, types.Int}, 370 rightTypes: []*types.T{types.Int, types.Int}, 371 leftTuples: tuples{{-1, -1}, {0, 4}, {2, 1}, {3, 4}, {5, 4}}, 372 rightTuples: tuples{{0, 5}, {1, 3}, {3, 2}, {4, 6}}, 373 leftOutCols: []uint32{1}, 374 rightOutCols: []uint32{1}, 375 leftEqCols: []uint32{0}, 376 rightEqCols: []uint32{0}, 377 expected: tuples{{4, 5}, {4, 2}}, 378 }, 379 { 380 description: "multi output column test, batch size = 1 and runs (to test saved output), reordered out columns", 381 leftTypes: []*types.T{types.Int, types.Int}, 382 rightTypes: []*types.T{types.Int, types.Int}, 383 leftTuples: tuples{{1, 10}, {1, 10}, {1, 10}, {2, 20}, {3, 30}, {4, 40}}, 384 rightTuples: tuples{{1, 11}, {1, 11}, {2, 12}, {3, 13}, {4, 14}}, 385 leftOutCols: []uint32{1, 0}, 386 rightOutCols: []uint32{1, 0}, 387 leftEqCols: []uint32{0}, 388 rightEqCols: []uint32{0}, 389 expected: tuples{ 390 {10, 1, 11, 1}, 391 {10, 1, 11, 1}, 392 {10, 1, 11, 1}, 393 {10, 1, 11, 1}, 394 {10, 1, 11, 1}, 395 {10, 1, 11, 1}, 396 {20, 2, 12, 2}, 397 {30, 3, 13, 3}, 398 {40, 4, 14, 4}, 399 }, 400 outputBatchSize: 1, 401 }, 402 { 403 description: "multi output column test, batch size = 1 and runs (to test saved output), reordered out columns that dont start at 0", 404 leftTypes: []*types.T{types.Int, types.Int}, 405 rightTypes: []*types.T{types.Int, types.Int}, 406 leftTuples: tuples{{1, 10}, {1, 10}, {1, 10}, {2, 20}, {3, 30}, {4, 40}}, 407 rightTuples: tuples{{1, 11}, {1, 11}, {2, 12}, {3, 13}, {4, 14}}, 408 leftOutCols: []uint32{1, 0}, 409 rightOutCols: []uint32{1}, 410 leftEqCols: []uint32{0}, 411 rightEqCols: []uint32{0}, 412 expected: tuples{ 413 {10, 1, 11}, 414 {10, 1, 11}, 415 {10, 1, 11}, 416 {10, 1, 11}, 417 {10, 1, 11}, 418 {10, 1, 11}, 419 {20, 2, 12}, 420 {30, 3, 13}, 421 {40, 4, 14}, 422 }, 423 outputBatchSize: 1, 424 }, 425 { 426 description: "equality column is correctly indexed", 427 leftTypes: []*types.T{types.Int, types.Int}, 428 rightTypes: []*types.T{types.Int, types.Int}, 429 leftTuples: tuples{{10, 1}, {10, 1}, {10, 1}, {20, 2}, {30, 3}, {40, 4}}, 430 rightTuples: tuples{{1, 11}, {1, 11}, {2, 12}, {3, 13}, {4, 14}}, 431 leftOutCols: []uint32{1, 0}, 432 rightOutCols: []uint32{1}, 433 leftEqCols: []uint32{1}, 434 rightEqCols: []uint32{0}, 435 expected: tuples{ 436 {1, 10, 11}, 437 {1, 10, 11}, 438 {1, 10, 11}, 439 {1, 10, 11}, 440 {1, 10, 11}, 441 {1, 10, 11}, 442 {2, 20, 12}, 443 {3, 30, 13}, 444 {4, 40, 14}, 445 }, 446 }, 447 { 448 description: "multi column equality basic test", 449 leftTypes: []*types.T{types.Int, types.Int}, 450 rightTypes: []*types.T{types.Int, types.Int}, 451 leftTuples: tuples{{1, 10}, {2, 20}, {3, 30}, {4, 40}}, 452 rightTuples: tuples{{1, 10}, {2, 20}, {3, 13}, {4, 14}}, 453 leftOutCols: []uint32{0, 1}, 454 rightOutCols: []uint32{0, 1}, 455 leftEqCols: []uint32{0, 1}, 456 rightEqCols: []uint32{0, 1}, 457 expected: tuples{ 458 {1, 10, 1, 10}, 459 {2, 20, 2, 20}, 460 }, 461 }, 462 { 463 description: "multi column equality runs", 464 leftTypes: []*types.T{types.Int, types.Int}, 465 rightTypes: []*types.T{types.Int, types.Int}, 466 leftTuples: tuples{{1, 10}, {1, 10}, {1, 10}, {2, 20}, {3, 30}, {4, 40}}, 467 rightTuples: tuples{{1, 10}, {1, 10}, {2, 20}, {3, 13}, {4, 14}}, 468 leftOutCols: []uint32{0, 1}, 469 rightOutCols: []uint32{0, 1}, 470 leftEqCols: []uint32{0, 1}, 471 rightEqCols: []uint32{0, 1}, 472 expected: tuples{ 473 {1, 10, 1, 10}, 474 {1, 10, 1, 10}, 475 {1, 10, 1, 10}, 476 {1, 10, 1, 10}, 477 {1, 10, 1, 10}, 478 {1, 10, 1, 10}, 479 {2, 20, 2, 20}, 480 }, 481 }, 482 { 483 description: "multi column non-consecutive equality cols", 484 leftTypes: []*types.T{types.Int, types.Int, types.Int}, 485 rightTypes: []*types.T{types.Int, types.Int, types.Int}, 486 leftTuples: tuples{{1, 123, 1}, {1, 234, 10}}, 487 rightTuples: tuples{{1, 1, 345}, {1, 10, 456}}, 488 leftOutCols: []uint32{0, 2, 1}, 489 rightOutCols: []uint32{0, 2, 1}, 490 leftEqCols: []uint32{0, 2}, 491 rightEqCols: []uint32{0, 1}, 492 expected: tuples{ 493 {1, 1, 123, 1, 345, 1}, 494 {1, 10, 234, 1, 456, 10}, 495 }, 496 }, 497 { 498 description: "multi column equality: new batch ends run", 499 leftTypes: []*types.T{types.Int, types.Int}, 500 rightTypes: []*types.T{types.Int, types.Int}, 501 leftTuples: tuples{{1, 1}, {1, 1}, {3, 3}, {4, 3}}, 502 rightTuples: tuples{{1, 1}, {1, 2}, {3, 3}, {3, 3}}, 503 leftOutCols: []uint32{0, 1}, 504 rightOutCols: []uint32{0, 1}, 505 leftEqCols: []uint32{0, 1}, 506 rightEqCols: []uint32{0, 1}, 507 expected: tuples{ 508 {1, 1, 1, 1}, 509 {1, 1, 1, 1}, 510 {3, 3, 3, 3}, 511 {3, 3, 3, 3}, 512 }, 513 }, 514 { 515 description: "multi column equality: reordered eq columns", 516 leftTypes: []*types.T{types.Int, types.Int}, 517 rightTypes: []*types.T{types.Int, types.Int}, 518 leftTuples: tuples{{1, 1}, {1, 1}, {3, 3}, {4, 3}}, 519 rightTuples: tuples{{1, 1}, {1, 2}, {3, 3}, {3, 3}}, 520 leftOutCols: []uint32{0, 1}, 521 rightOutCols: []uint32{0, 1}, 522 leftEqCols: []uint32{0, 1}, 523 rightEqCols: []uint32{1, 0}, 524 expected: tuples{ 525 {1, 1, 1, 1}, 526 {1, 1, 1, 1}, 527 {3, 3, 3, 3}, 528 {3, 3, 3, 3}, 529 }, 530 }, 531 { 532 description: "cross batch, distinct group", 533 leftTypes: []*types.T{types.Int, types.Int}, 534 rightTypes: []*types.T{types.Int, types.Int}, 535 leftTuples: tuples{{1, 2}, {1, 2}, {1, 2}, {2, 2}}, 536 rightTuples: tuples{{1, 2}}, 537 leftOutCols: []uint32{0, 1}, 538 rightOutCols: []uint32{0, 1}, 539 leftEqCols: []uint32{0, 1}, 540 rightEqCols: []uint32{0, 1}, 541 expected: tuples{ 542 {1, 2, 1, 2}, 543 {1, 2, 1, 2}, 544 {1, 2, 1, 2}, 545 }, 546 }, 547 { 548 description: "templating basic test", 549 leftTypes: []*types.T{types.Bool, types.Int2, types.Float}, 550 rightTypes: []*types.T{types.Bool, types.Int2, types.Float}, 551 leftTuples: tuples{{true, int16(10), 1.2}, {true, int16(20), 2.2}, {true, int16(30), 3.2}}, 552 rightTuples: tuples{{true, int16(10), 1.2}, {false, int16(20), 2.2}, {true, int16(30), 3.9}}, 553 leftOutCols: []uint32{0, 1, 2}, 554 rightOutCols: []uint32{0, 1, 2}, 555 leftEqCols: []uint32{0, 1, 2}, 556 rightEqCols: []uint32{0, 1, 2}, 557 expected: tuples{ 558 {true, 10, 1.2, true, 10, 1.2}, 559 }, 560 }, 561 { 562 description: "templating cross product test", 563 leftTypes: []*types.T{types.Bool, types.Int2, types.Float}, 564 rightTypes: []*types.T{types.Bool, types.Int2, types.Float}, 565 leftTuples: tuples{{false, int16(10), 1.2}, {true, int16(20), 2.2}, {true, int16(30), 3.2}}, 566 rightTuples: tuples{{false, int16(10), 1.2}, {true, int16(20), 2.3}, {true, int16(20), 2.4}, {true, int16(31), 3.9}}, 567 leftOutCols: []uint32{0, 1, 2}, 568 rightOutCols: []uint32{0, 1, 2}, 569 leftEqCols: []uint32{0, 1}, 570 rightEqCols: []uint32{0, 1}, 571 expected: tuples{ 572 {false, 10, 1.2, false, 10, 1.2}, 573 {true, 20, 2.2, true, 20, 2.3}, 574 {true, 20, 2.2, true, 20, 2.4}, 575 }, 576 }, 577 { 578 description: "templating cross product test, output batch size 1", 579 leftTypes: []*types.T{types.Bool, types.Int2, types.Float}, 580 rightTypes: []*types.T{types.Bool, types.Int2, types.Float}, 581 leftTuples: tuples{{false, int16(10), 1.2}, {true, int16(20), 2.2}, {true, int16(30), 3.2}}, 582 rightTuples: tuples{{false, int16(10), 1.2}, {true, int16(20), 2.3}, {true, int16(20), 2.4}, {true, int16(31), 3.9}}, 583 leftOutCols: []uint32{0, 1, 2}, 584 rightOutCols: []uint32{0, 1, 2}, 585 leftEqCols: []uint32{0, 1}, 586 rightEqCols: []uint32{0, 1}, 587 expected: tuples{ 588 {false, 10, 1.2, false, 10, 1.2}, 589 {true, 20, 2.2, true, 20, 2.3}, 590 {true, 20, 2.2, true, 20, 2.4}, 591 }, 592 outputBatchSize: 1, 593 }, 594 { 595 description: "templating cross product test, output batch size 2", 596 leftTypes: []*types.T{types.Bool, types.Int2, types.Float}, 597 rightTypes: []*types.T{types.Bool, types.Int2, types.Float}, 598 leftTuples: tuples{{false, int16(10), 1.2}, {true, int16(20), 2.2}, {true, int16(30), 3.2}}, 599 rightTuples: tuples{{false, int16(10), 1.2}, {true, int16(20), 2.3}, {true, int16(20), 2.4}, {true, int16(31), 3.9}}, 600 leftOutCols: []uint32{0, 1, 2}, 601 rightOutCols: []uint32{0, 1, 2}, 602 leftEqCols: []uint32{0, 1}, 603 rightEqCols: []uint32{0, 1}, 604 expected: tuples{ 605 {false, 10, 1.2, false, 10, 1.2}, 606 {true, 20, 2.2, true, 20, 2.3}, 607 {true, 20, 2.2, true, 20, 2.4}, 608 }, 609 outputBatchSize: 2, 610 }, 611 { 612 description: "templating reordered eq columns", 613 leftTypes: []*types.T{types.Bool, types.Int2, types.Float}, 614 rightTypes: []*types.T{types.Bool, types.Int2, types.Float}, 615 leftTuples: tuples{{false, int16(10), 1.2}, {true, int16(20), 2.2}, {true, int16(30), 3.2}}, 616 rightTuples: tuples{{false, int16(10), 1.2}, {true, int16(20), 2.3}, {true, int16(20), 2.4}, {true, int16(31), 3.9}}, 617 leftOutCols: []uint32{0, 1, 2}, 618 rightOutCols: []uint32{0, 1, 2}, 619 leftEqCols: []uint32{1, 0}, 620 rightEqCols: []uint32{1, 0}, 621 expected: tuples{ 622 {false, 10, 1.2, false, 10, 1.2}, 623 {true, 20, 2.2, true, 20, 2.3}, 624 {true, 20, 2.2, true, 20, 2.4}, 625 }, 626 }, 627 { 628 description: "templating reordered eq columns non symmetrical", 629 leftTypes: []*types.T{types.Bool, types.Int2, types.Float}, 630 rightTypes: []*types.T{types.Int2, types.Float, types.Bool}, 631 leftTuples: tuples{{false, int16(10), 1.2}, {true, int16(20), 2.2}, {true, int16(30), 3.2}}, 632 rightTuples: tuples{{int16(10), 1.2, false}, {int16(20), 2.2, true}, {int16(21), 2.2, true}, {int16(30), 3.2, false}}, 633 leftOutCols: []uint32{0, 1, 2}, 634 rightOutCols: []uint32{0, 1, 2}, 635 leftEqCols: []uint32{2, 0}, 636 rightEqCols: []uint32{1, 2}, 637 expected: tuples{ 638 {false, 10, 1.2, 10, 1.2, false}, 639 {true, 20, 2.2, 20, 2.2, true}, 640 {true, 20, 2.2, 21, 2.2, true}, 641 }, 642 }, 643 { 644 description: "null handling", 645 leftTypes: []*types.T{types.Int}, 646 rightTypes: []*types.T{types.Int}, 647 leftTuples: tuples{{nil}, {0}}, 648 rightTuples: tuples{{nil}, {0}}, 649 leftOutCols: []uint32{0}, 650 rightOutCols: []uint32{0}, 651 leftEqCols: []uint32{0}, 652 rightEqCols: []uint32{0}, 653 expected: tuples{ 654 {0, 0}, 655 }, 656 }, 657 { 658 description: "null handling multi column, nulls on left", 659 leftTypes: []*types.T{types.Int, types.Int}, 660 rightTypes: []*types.T{types.Int, types.Int}, 661 leftTuples: tuples{{nil, 0}, {0, nil}}, 662 rightTuples: tuples{{nil, nil}, {0, 1}}, 663 leftOutCols: []uint32{0, 1}, 664 rightOutCols: []uint32{0, 1}, 665 leftEqCols: []uint32{0}, 666 rightEqCols: []uint32{0}, 667 expected: tuples{ 668 {0, nil, 0, 1}, 669 }, 670 }, 671 { 672 description: "null handling multi column, nulls on right", 673 leftTypes: []*types.T{types.Int, types.Int}, 674 rightTypes: []*types.T{types.Int, types.Int}, 675 leftTuples: tuples{{nil, 0}, {0, 1}}, 676 rightTuples: tuples{{nil, nil}, {0, nil}}, 677 leftOutCols: []uint32{0, 1}, 678 rightOutCols: []uint32{0, 1}, 679 leftEqCols: []uint32{0}, 680 rightEqCols: []uint32{0}, 681 expected: tuples{ 682 {0, 1, 0, nil}, 683 }, 684 }, 685 { 686 description: "desc test", 687 leftTypes: []*types.T{types.Int}, 688 rightTypes: []*types.T{types.Int}, 689 leftTuples: tuples{{4}, {3}, {2}, {1}}, 690 rightTuples: tuples{{4}, {2}, {1}}, 691 leftOutCols: []uint32{0}, 692 rightOutCols: []uint32{0}, 693 leftEqCols: []uint32{0}, 694 rightEqCols: []uint32{0}, 695 expected: tuples{{4, 4}, {2, 2}, {1, 1}}, 696 697 leftDirections: []execinfrapb.Ordering_Column_Direction{execinfrapb.Ordering_Column_DESC}, 698 rightDirections: []execinfrapb.Ordering_Column_Direction{execinfrapb.Ordering_Column_DESC}, 699 }, 700 { 701 description: "desc nulls test", 702 leftTypes: []*types.T{types.Int}, 703 rightTypes: []*types.T{types.Int}, 704 leftTuples: tuples{{4}, {3}, {nil}, {1}}, 705 rightTuples: tuples{{4}, {nil}, {2}, {1}}, 706 leftOutCols: []uint32{0}, 707 rightOutCols: []uint32{0}, 708 leftEqCols: []uint32{0}, 709 rightEqCols: []uint32{0}, 710 expected: tuples{{4, 4}, {1, 1}}, 711 712 leftDirections: []execinfrapb.Ordering_Column_Direction{execinfrapb.Ordering_Column_DESC}, 713 rightDirections: []execinfrapb.Ordering_Column_Direction{execinfrapb.Ordering_Column_DESC}, 714 }, 715 { 716 description: "desc nulls test end on 0", 717 leftTypes: []*types.T{types.Int}, 718 rightTypes: []*types.T{types.Int}, 719 leftTuples: tuples{{9}, {9}, {8}, {0}, {nil}}, 720 rightTuples: tuples{{9}, {9}, {8}, {0}, {nil}}, 721 leftOutCols: []uint32{0}, 722 rightOutCols: []uint32{0}, 723 leftEqCols: []uint32{0}, 724 rightEqCols: []uint32{0}, 725 expected: tuples{{9, 9}, {9, 9}, {9, 9}, {9, 9}, {8, 8}, {0, 0}}, 726 727 leftDirections: []execinfrapb.Ordering_Column_Direction{execinfrapb.Ordering_Column_DESC}, 728 rightDirections: []execinfrapb.Ordering_Column_Direction{execinfrapb.Ordering_Column_DESC}, 729 }, 730 { 731 description: "non-equality columns with nulls", 732 leftTypes: []*types.T{types.Int, types.Int}, 733 rightTypes: []*types.T{types.Int, types.Int}, 734 leftTuples: tuples{{1, nil}, {2, 2}, {2, 2}, {3, nil}, {4, nil}}, 735 rightTuples: tuples{{1, 1}, {2, nil}, {2, nil}, {3, nil}, {4, 4}, {4, 4}}, 736 leftOutCols: []uint32{0, 1}, 737 rightOutCols: []uint32{0, 1}, 738 leftEqCols: []uint32{0}, 739 rightEqCols: []uint32{0}, 740 expected: tuples{{1, nil, 1, 1}, {2, 2, 2, nil}, {2, 2, 2, nil}, {2, 2, 2, nil}, {2, 2, 2, nil}, {3, nil, 3, nil}, {4, nil, 4, 4}, {4, nil, 4, 4}}, 741 }, 742 { 743 description: "basic LEFT OUTER JOIN test, L and R exhausted at the same time", 744 joinType: sqlbase.LeftOuterJoin, 745 leftTypes: []*types.T{types.Int}, 746 rightTypes: []*types.T{types.Int}, 747 leftTuples: tuples{{1}, {2}, {3}, {4}, {4}}, 748 rightTuples: tuples{{0}, {2}, {3}, {4}, {4}}, 749 leftOutCols: []uint32{0}, 750 rightOutCols: []uint32{0}, 751 leftEqCols: []uint32{0}, 752 rightEqCols: []uint32{0}, 753 expected: tuples{{1, nil}, {2, 2}, {3, 3}, {4, 4}, {4, 4}, {4, 4}, {4, 4}}, 754 }, 755 { 756 description: "basic LEFT OUTER JOIN test, R exhausted first", 757 joinType: sqlbase.LeftOuterJoin, 758 leftTypes: []*types.T{types.Int}, 759 rightTypes: []*types.T{types.Int}, 760 leftTuples: tuples{{1}, {1}, {3}, {5}, {6}, {7}}, 761 rightTuples: tuples{{2}, {3}, {4}}, 762 leftOutCols: []uint32{0}, 763 rightOutCols: []uint32{0}, 764 leftEqCols: []uint32{0}, 765 rightEqCols: []uint32{0}, 766 expected: tuples{{1, nil}, {1, nil}, {3, 3}, {5, nil}, {6, nil}, {7, nil}}, 767 }, 768 { 769 description: "basic LEFT OUTER JOIN test, L exhausted first", 770 joinType: sqlbase.LeftOuterJoin, 771 leftTypes: []*types.T{types.Int}, 772 rightTypes: []*types.T{types.Int}, 773 leftTuples: tuples{{3}, {5}, {6}, {7}}, 774 rightTuples: tuples{{2}, {3}, {4}, {6}, {8}, {9}}, 775 leftOutCols: []uint32{0}, 776 rightOutCols: []uint32{0}, 777 leftEqCols: []uint32{0}, 778 rightEqCols: []uint32{0}, 779 expected: tuples{{3, 3}, {5, nil}, {6, 6}, {7, nil}}, 780 }, 781 { 782 description: "multi output column LEFT OUTER JOIN test with nulls", 783 joinType: sqlbase.LeftOuterJoin, 784 leftTypes: []*types.T{types.Int, types.Int}, 785 rightTypes: []*types.T{types.Int, types.Int}, 786 leftTuples: tuples{{1, 10}, {2, 20}, {3, nil}, {4, 40}}, 787 rightTuples: tuples{{1, nil}, {3, 13}, {4, 14}}, 788 leftOutCols: []uint32{0, 1}, 789 rightOutCols: []uint32{0, 1}, 790 leftEqCols: []uint32{0}, 791 rightEqCols: []uint32{0}, 792 expected: tuples{{1, 10, 1, nil}, {2, 20, nil, nil}, {3, nil, 3, 13}, {4, 40, 4, 14}}, 793 }, 794 { 795 description: "null in equality column LEFT OUTER JOIN", 796 joinType: sqlbase.LeftOuterJoin, 797 leftTypes: []*types.T{types.Int}, 798 rightTypes: []*types.T{types.Int, types.Int}, 799 leftTuples: tuples{{nil}, {nil}, {1}, {3}}, 800 rightTuples: tuples{{nil, 1}, {1, 1}, {2, 2}, {3, 3}}, 801 leftOutCols: []uint32{0}, 802 rightOutCols: []uint32{0, 1}, 803 leftEqCols: []uint32{0}, 804 rightEqCols: []uint32{0}, 805 expected: tuples{{nil, nil, nil}, {nil, nil, nil}, {1, 1, 1}, {3, 3, 3}}, 806 }, 807 { 808 description: "multi equality column LEFT OUTER JOIN test with nulls", 809 joinType: sqlbase.LeftOuterJoin, 810 leftTypes: []*types.T{types.Int, types.Int}, 811 rightTypes: []*types.T{types.Int, types.Int}, 812 leftTuples: tuples{{nil, nil}, {nil, 10}, {1, nil}, {1, 10}, {2, 20}, {4, 40}}, 813 rightTuples: tuples{{nil, nil}, {nil, 10}, {1, nil}, {1, nil}, {2, 20}, {3, 30}}, 814 leftOutCols: []uint32{0, 1}, 815 rightOutCols: []uint32{0, 1}, 816 leftEqCols: []uint32{0, 1}, 817 rightEqCols: []uint32{0, 1}, 818 expected: tuples{{nil, nil, nil, nil}, {nil, 10, nil, nil}, {1, nil, nil, nil}, {1, 10, nil, nil}, {2, 20, 2, 20}, {4, 40, nil, nil}}, 819 }, 820 { 821 description: "multi equality column (long runs on left) LEFT OUTER JOIN test with nulls", 822 joinType: sqlbase.LeftOuterJoin, 823 leftTypes: []*types.T{types.Int, types.Int}, 824 rightTypes: []*types.T{types.Int, types.Int}, 825 leftTuples: tuples{{1, 9}, {1, 10}, {1, 10}, {1, 11}, {2, 20}, {2, 20}, {2, 21}, {2, 22}, {2, 22}}, 826 rightTuples: tuples{{1, 8}, {1, 11}, {1, 11}, {2, 21}, {2, 23}}, 827 leftOutCols: []uint32{0, 1}, 828 rightOutCols: []uint32{0, 1}, 829 leftEqCols: []uint32{0, 1}, 830 rightEqCols: []uint32{0, 1}, 831 expected: tuples{{1, 9, nil, nil}, {1, 10, nil, nil}, {1, 10, nil, nil}, {1, 11, 1, 11}, {1, 11, 1, 11}, {2, 20, nil, nil}, {2, 20, nil, nil}, {2, 21, 2, 21}, {2, 22, nil, nil}, {2, 22, nil, nil}}, 832 }, 833 { 834 description: "3 equality column LEFT OUTER JOIN test with nulls DESC ordering", 835 joinType: sqlbase.LeftOuterJoin, 836 leftTypes: []*types.T{types.Int, types.Int, types.Int}, 837 rightTypes: []*types.T{types.Int, types.Int, types.Int}, 838 leftDirections: []execinfrapb.Ordering_Column_Direction{execinfrapb.Ordering_Column_DESC, execinfrapb.Ordering_Column_DESC, execinfrapb.Ordering_Column_DESC}, 839 rightDirections: []execinfrapb.Ordering_Column_Direction{execinfrapb.Ordering_Column_DESC, execinfrapb.Ordering_Column_DESC, execinfrapb.Ordering_Column_DESC}, 840 leftTuples: tuples{{2, 3, 1}, {2, nil, 1}, {nil, 1, 3}}, 841 rightTuples: tuples{{4, 3, 3}, {nil, 2, nil}, {nil, 1, 3}}, 842 leftOutCols: []uint32{0, 1, 2}, 843 rightOutCols: []uint32{0, 1, 2}, 844 leftEqCols: []uint32{0, 1, 2}, 845 rightEqCols: []uint32{0, 1, 2}, 846 expected: tuples{{2, 3, 1, nil, nil, nil}, {2, nil, 1, nil, nil, nil}, {nil, 1, 3, nil, nil, nil}}, 847 }, 848 { 849 description: "3 equality column LEFT OUTER JOIN test with nulls mixed ordering", 850 joinType: sqlbase.LeftOuterJoin, 851 leftTypes: []*types.T{types.Int, types.Int, types.Int}, 852 rightTypes: []*types.T{types.Int, types.Int, types.Int}, 853 leftDirections: []execinfrapb.Ordering_Column_Direction{execinfrapb.Ordering_Column_DESC, execinfrapb.Ordering_Column_DESC, execinfrapb.Ordering_Column_ASC}, 854 rightDirections: []execinfrapb.Ordering_Column_Direction{execinfrapb.Ordering_Column_ASC, execinfrapb.Ordering_Column_DESC, execinfrapb.Ordering_Column_DESC}, 855 leftTuples: tuples{{2, 3, 1}, {2, nil, 1}, {nil, 1, 3}}, 856 rightTuples: tuples{{4, 3, 3}, {nil, 2, nil}, {nil, 1, 3}}, 857 leftOutCols: []uint32{0, 1, 2}, 858 rightOutCols: []uint32{0, 1, 2}, 859 leftEqCols: []uint32{0, 1, 2}, 860 rightEqCols: []uint32{1, 2, 0}, 861 expected: tuples{{2, 3, 1, nil, nil, nil}, {2, nil, 1, nil, nil, nil}, {nil, 1, 3, nil, nil, nil}}, 862 }, 863 { 864 description: "single column DESC with nulls on the left LEFT OUTER JOIN", 865 joinType: sqlbase.LeftOuterJoin, 866 leftTypes: []*types.T{types.Int}, 867 rightTypes: []*types.T{types.Int}, 868 leftDirections: []execinfrapb.Ordering_Column_Direction{execinfrapb.Ordering_Column_DESC}, 869 rightDirections: []execinfrapb.Ordering_Column_Direction{execinfrapb.Ordering_Column_DESC}, 870 leftTuples: tuples{{1}, {1}, {1}, {nil}, {nil}, {nil}}, 871 rightTuples: tuples{{1}}, 872 leftOutCols: []uint32{0}, 873 rightOutCols: []uint32{0}, 874 leftEqCols: []uint32{0}, 875 rightEqCols: []uint32{0}, 876 expected: tuples{{1, 1}, {1, 1}, {1, 1}, {nil, nil}, {nil, nil}, {nil, nil}}, 877 }, 878 { 879 description: "basic RIGHT OUTER JOIN test, L and R exhausted at the same time", 880 joinType: sqlbase.RightOuterJoin, 881 leftTypes: []*types.T{types.Int}, 882 rightTypes: []*types.T{types.Int}, 883 leftTuples: tuples{{-1}, {2}, {3}, {4}, {4}}, 884 rightTuples: tuples{{1}, {2}, {3}, {4}, {4}}, 885 leftOutCols: []uint32{0}, 886 rightOutCols: []uint32{0}, 887 leftEqCols: []uint32{0}, 888 rightEqCols: []uint32{0}, 889 expected: tuples{{nil, 1}, {2, 2}, {3, 3}, {4, 4}, {4, 4}, {4, 4}, {4, 4}}, 890 }, 891 { 892 description: "basic RIGHT OUTER JOIN test, R exhausted first", 893 joinType: sqlbase.RightOuterJoin, 894 leftTypes: []*types.T{types.Int}, 895 rightTypes: []*types.T{types.Int}, 896 leftTuples: tuples{{1}, {1}, {3}, {5}, {6}, {7}}, 897 rightTuples: tuples{{2}, {3}, {4}}, 898 leftOutCols: []uint32{0}, 899 rightOutCols: []uint32{0}, 900 leftEqCols: []uint32{0}, 901 rightEqCols: []uint32{0}, 902 expected: tuples{{nil, 2}, {3, 3}, {nil, 4}}, 903 }, 904 { 905 description: "basic RIGHT OUTER JOIN test, L exhausted first", 906 joinType: sqlbase.RightOuterJoin, 907 leftTypes: []*types.T{types.Int}, 908 rightTypes: []*types.T{types.Int}, 909 leftTuples: tuples{{3}, {5}, {6}, {7}}, 910 rightTuples: tuples{{2}, {3}, {4}, {6}, {8}, {9}}, 911 leftOutCols: []uint32{0}, 912 rightOutCols: []uint32{0}, 913 leftEqCols: []uint32{0}, 914 rightEqCols: []uint32{0}, 915 expected: tuples{{nil, 2}, {3, 3}, {nil, 4}, {6, 6}, {nil, 8}, {nil, 9}}, 916 }, 917 { 918 description: "multi output column RIGHT OUTER JOIN test with nulls", 919 joinType: sqlbase.RightOuterJoin, 920 leftTypes: []*types.T{types.Int, types.Int}, 921 rightTypes: []*types.T{types.Int, types.Int}, 922 leftTuples: tuples{{1, nil}, {3, 13}, {4, 14}}, 923 rightTuples: tuples{{1, 10}, {2, 20}, {3, nil}, {4, 40}}, 924 leftOutCols: []uint32{0, 1}, 925 rightOutCols: []uint32{0, 1}, 926 leftEqCols: []uint32{0}, 927 rightEqCols: []uint32{0}, 928 expected: tuples{{1, nil, 1, 10}, {nil, nil, 2, 20}, {3, 13, 3, nil}, {4, 14, 4, 40}}, 929 }, 930 { 931 description: "null in equality column RIGHT OUTER JOIN", 932 joinType: sqlbase.RightOuterJoin, 933 leftTypes: []*types.T{types.Int, types.Int}, 934 rightTypes: []*types.T{types.Int}, 935 leftTuples: tuples{{nil, 1}, {1, 1}, {2, 2}, {3, 3}}, 936 rightTuples: tuples{{nil}, {nil}, {1}, {3}}, 937 leftOutCols: []uint32{0, 1}, 938 rightOutCols: []uint32{0}, 939 leftEqCols: []uint32{0}, 940 rightEqCols: []uint32{0}, 941 expected: tuples{{nil, nil, nil}, {nil, nil, nil}, {1, 1, 1}, {3, 3, 3}}, 942 }, 943 { 944 description: "multi equality column RIGHT OUTER JOIN test with nulls", 945 joinType: sqlbase.RightOuterJoin, 946 leftTypes: []*types.T{types.Int, types.Int}, 947 rightTypes: []*types.T{types.Int, types.Int}, 948 leftTuples: tuples{{nil, nil}, {nil, 10}, {1, nil}, {1, nil}, {2, 20}, {3, 30}}, 949 rightTuples: tuples{{nil, nil}, {nil, 10}, {1, nil}, {1, 10}, {2, 20}, {4, 40}}, 950 leftOutCols: []uint32{0, 1}, 951 rightOutCols: []uint32{0, 1}, 952 leftEqCols: []uint32{0, 1}, 953 rightEqCols: []uint32{0, 1}, 954 expected: tuples{{nil, nil, nil, nil}, {nil, nil, nil, 10}, {nil, nil, 1, nil}, {nil, nil, 1, 10}, {2, 20, 2, 20}, {nil, nil, 4, 40}}, 955 }, 956 { 957 description: "multi equality column (long runs on right) RIGHT OUTER JOIN test with nulls", 958 joinType: sqlbase.RightOuterJoin, 959 leftTypes: []*types.T{types.Int, types.Int}, 960 rightTypes: []*types.T{types.Int, types.Int}, 961 leftTuples: tuples{{1, 8}, {1, 11}, {1, 11}, {2, 21}, {2, 23}}, 962 rightTuples: tuples{{1, 9}, {1, 10}, {1, 10}, {1, 11}, {2, 20}, {2, 20}, {2, 21}, {2, 22}, {2, 22}}, 963 leftOutCols: []uint32{0, 1}, 964 rightOutCols: []uint32{0, 1}, 965 leftEqCols: []uint32{0, 1}, 966 rightEqCols: []uint32{0, 1}, 967 expected: tuples{{nil, nil, 1, 9}, {nil, nil, 1, 10}, {nil, nil, 1, 10}, {1, 11, 1, 11}, {1, 11, 1, 11}, {nil, nil, 2, 20}, {nil, nil, 2, 20}, {2, 21, 2, 21}, {nil, nil, 2, 22}, {nil, nil, 2, 22}}, 968 }, 969 { 970 description: "3 equality column RIGHT OUTER JOIN test with nulls DESC ordering", 971 joinType: sqlbase.RightOuterJoin, 972 leftTypes: []*types.T{types.Int, types.Int, types.Int}, 973 rightTypes: []*types.T{types.Int, types.Int, types.Int}, 974 leftDirections: []execinfrapb.Ordering_Column_Direction{execinfrapb.Ordering_Column_DESC, execinfrapb.Ordering_Column_DESC, execinfrapb.Ordering_Column_DESC}, 975 rightDirections: []execinfrapb.Ordering_Column_Direction{execinfrapb.Ordering_Column_DESC, execinfrapb.Ordering_Column_DESC, execinfrapb.Ordering_Column_DESC}, 976 leftTuples: tuples{{4, 3, 3}, {nil, 2, nil}, {nil, 1, 3}}, 977 rightTuples: tuples{{2, 3, 1}, {2, nil, 1}, {nil, 1, 3}}, 978 leftOutCols: []uint32{0, 1, 2}, 979 rightOutCols: []uint32{0, 1, 2}, 980 leftEqCols: []uint32{0, 1, 2}, 981 rightEqCols: []uint32{0, 1, 2}, 982 expected: tuples{{nil, nil, nil, 2, 3, 1}, {nil, nil, nil, 2, nil, 1}, {nil, nil, nil, nil, 1, 3}}, 983 }, 984 { 985 description: "3 equality column RIGHT OUTER JOIN test with nulls mixed ordering", 986 joinType: sqlbase.RightOuterJoin, 987 leftTypes: []*types.T{types.Int, types.Int, types.Int}, 988 rightTypes: []*types.T{types.Int, types.Int, types.Int}, 989 leftDirections: []execinfrapb.Ordering_Column_Direction{execinfrapb.Ordering_Column_DESC, execinfrapb.Ordering_Column_DESC, execinfrapb.Ordering_Column_ASC}, 990 rightDirections: []execinfrapb.Ordering_Column_Direction{execinfrapb.Ordering_Column_ASC, execinfrapb.Ordering_Column_DESC, execinfrapb.Ordering_Column_DESC}, 991 leftTuples: tuples{{4, 3, 3}, {nil, 2, nil}, {nil, 1, 3}}, 992 rightTuples: tuples{{2, 3, 1}, {2, nil, 1}, {nil, 1, 3}}, 993 leftOutCols: []uint32{0, 1, 2}, 994 rightOutCols: []uint32{0, 1, 2}, 995 leftEqCols: []uint32{0, 1, 2}, 996 rightEqCols: []uint32{1, 2, 0}, 997 expected: tuples{{nil, nil, nil, 2, 3, 1}, {nil, nil, nil, 2, nil, 1}, {nil, nil, nil, nil, 1, 3}}, 998 }, 999 { 1000 description: "single column DESC with nulls on the right RIGHT OUTER JOIN", 1001 joinType: sqlbase.RightOuterJoin, 1002 leftTypes: []*types.T{types.Int}, 1003 rightTypes: []*types.T{types.Int}, 1004 leftDirections: []execinfrapb.Ordering_Column_Direction{execinfrapb.Ordering_Column_DESC}, 1005 rightDirections: []execinfrapb.Ordering_Column_Direction{execinfrapb.Ordering_Column_DESC}, 1006 leftTuples: tuples{{1}}, 1007 rightTuples: tuples{{1}, {1}, {1}, {nil}, {nil}, {nil}}, 1008 leftOutCols: []uint32{0}, 1009 rightOutCols: []uint32{0}, 1010 leftEqCols: []uint32{0}, 1011 rightEqCols: []uint32{0}, 1012 expected: tuples{{1, 1}, {1, 1}, {1, 1}, {nil, nil}, {nil, nil}, {nil, nil}}, 1013 }, 1014 { 1015 description: "basic FULL OUTER JOIN test, L and R exhausted at the same time", 1016 joinType: sqlbase.FullOuterJoin, 1017 leftTypes: []*types.T{types.Int}, 1018 rightTypes: []*types.T{types.Int}, 1019 leftTuples: tuples{{-1}, {2}, {3}, {4}, {4}}, 1020 rightTuples: tuples{{1}, {2}, {3}, {4}, {4}}, 1021 leftOutCols: []uint32{0}, 1022 rightOutCols: []uint32{0}, 1023 leftEqCols: []uint32{0}, 1024 rightEqCols: []uint32{0}, 1025 expected: tuples{{-1, nil}, {nil, 1}, {2, 2}, {3, 3}, {4, 4}, {4, 4}, {4, 4}, {4, 4}}, 1026 }, 1027 { 1028 description: "basic FULL OUTER JOIN test, R exhausted first", 1029 joinType: sqlbase.FullOuterJoin, 1030 leftTypes: []*types.T{types.Int}, 1031 rightTypes: []*types.T{types.Int}, 1032 leftTuples: tuples{{1}, {1}, {3}, {5}, {6}, {7}}, 1033 rightTuples: tuples{{2}, {3}, {4}}, 1034 leftOutCols: []uint32{0}, 1035 rightOutCols: []uint32{0}, 1036 leftEqCols: []uint32{0}, 1037 rightEqCols: []uint32{0}, 1038 expected: tuples{{1, nil}, {1, nil}, {nil, 2}, {3, 3}, {nil, 4}, {5, nil}, {6, nil}, {7, nil}}, 1039 }, 1040 { 1041 description: "basic FULL OUTER JOIN test, L exhausted first", 1042 joinType: sqlbase.FullOuterJoin, 1043 leftTypes: []*types.T{types.Int}, 1044 rightTypes: []*types.T{types.Int}, 1045 leftTuples: tuples{{3}, {5}, {6}, {7}}, 1046 rightTuples: tuples{{2}, {3}, {4}, {6}, {8}, {9}}, 1047 leftOutCols: []uint32{0}, 1048 rightOutCols: []uint32{0}, 1049 leftEqCols: []uint32{0}, 1050 rightEqCols: []uint32{0}, 1051 expected: tuples{{nil, 2}, {3, 3}, {nil, 4}, {5, nil}, {6, 6}, {7, nil}, {nil, 8}, {nil, 9}}, 1052 }, 1053 { 1054 description: "multi output column FULL OUTER JOIN test with nulls", 1055 joinType: sqlbase.FullOuterJoin, 1056 leftTypes: []*types.T{types.Int, types.Int}, 1057 rightTypes: []*types.T{types.Int, types.Int}, 1058 leftTuples: tuples{{1, nil}, {3, 13}, {4, 14}}, 1059 rightTuples: tuples{{1, 10}, {2, 20}, {3, nil}, {4, 40}}, 1060 leftOutCols: []uint32{0, 1}, 1061 rightOutCols: []uint32{0, 1}, 1062 leftEqCols: []uint32{0}, 1063 rightEqCols: []uint32{0}, 1064 expected: tuples{{1, nil, 1, 10}, {nil, nil, 2, 20}, {3, 13, 3, nil}, {4, 14, 4, 40}}, 1065 }, 1066 { 1067 description: "null in equality column FULL OUTER JOIN", 1068 joinType: sqlbase.FullOuterJoin, 1069 leftTypes: []*types.T{types.Int, types.Int}, 1070 rightTypes: []*types.T{types.Int}, 1071 leftTuples: tuples{{nil, 1}, {1, 1}, {2, 2}, {3, 3}}, 1072 rightTuples: tuples{{nil}, {nil}, {1}, {3}}, 1073 leftOutCols: []uint32{0, 1}, 1074 rightOutCols: []uint32{0}, 1075 leftEqCols: []uint32{0}, 1076 rightEqCols: []uint32{0}, 1077 expected: tuples{{nil, 1, nil}, {nil, nil, nil}, {nil, nil, nil}, {1, 1, 1}, {2, 2, nil}, {3, 3, 3}}, 1078 }, 1079 { 1080 description: "multi equality column FULL OUTER JOIN test with nulls", 1081 joinType: sqlbase.FullOuterJoin, 1082 leftTypes: []*types.T{types.Int, types.Int}, 1083 rightTypes: []*types.T{types.Int, types.Int}, 1084 leftTuples: tuples{{nil, nil}, {nil, 10}, {1, nil}, {1, nil}, {2, 20}, {3, 30}}, 1085 rightTuples: tuples{{nil, nil}, {nil, 10}, {1, nil}, {1, 10}, {2, 20}, {4, 40}}, 1086 leftOutCols: []uint32{0, 1}, 1087 rightOutCols: []uint32{0, 1}, 1088 leftEqCols: []uint32{0, 1}, 1089 rightEqCols: []uint32{0, 1}, 1090 expected: tuples{{nil, nil, nil, nil}, {nil, nil, nil, nil}, {nil, 10, nil, nil}, {nil, nil, nil, 10}, {1, nil, nil, nil}, {1, nil, nil, nil}, {nil, nil, 1, nil}, {nil, nil, 1, 10}, {2, 20, 2, 20}, {3, 30, nil, nil}, {nil, nil, 4, 40}}, 1091 }, 1092 { 1093 description: "multi equality column (long runs on right) FULL OUTER JOIN test with nulls", 1094 joinType: sqlbase.FullOuterJoin, 1095 leftTypes: []*types.T{types.Int, types.Int}, 1096 rightTypes: []*types.T{types.Int, types.Int}, 1097 leftTuples: tuples{{1, 8}, {1, 11}, {1, 11}, {2, 21}, {2, 23}}, 1098 rightTuples: tuples{{1, 9}, {1, 10}, {1, 10}, {1, 11}, {2, 20}, {2, 20}, {2, 21}, {2, 22}, {2, 22}}, 1099 leftOutCols: []uint32{0, 1}, 1100 rightOutCols: []uint32{0, 1}, 1101 leftEqCols: []uint32{0, 1}, 1102 rightEqCols: []uint32{0, 1}, 1103 expected: tuples{{1, 8, nil, nil}, {nil, nil, 1, 9}, {nil, nil, 1, 10}, {nil, nil, 1, 10}, {1, 11, 1, 11}, {1, 11, 1, 11}, {nil, nil, 2, 20}, {nil, nil, 2, 20}, {2, 21, 2, 21}, {nil, nil, 2, 22}, {nil, nil, 2, 22}, {2, 23, nil, nil}}, 1104 }, 1105 { 1106 description: "3 equality column FULL OUTER JOIN test with nulls DESC ordering", 1107 joinType: sqlbase.FullOuterJoin, 1108 leftTypes: []*types.T{types.Int, types.Int, types.Int}, 1109 rightTypes: []*types.T{types.Int, types.Int, types.Int}, 1110 leftDirections: []execinfrapb.Ordering_Column_Direction{execinfrapb.Ordering_Column_DESC, execinfrapb.Ordering_Column_DESC, execinfrapb.Ordering_Column_DESC}, 1111 rightDirections: []execinfrapb.Ordering_Column_Direction{execinfrapb.Ordering_Column_DESC, execinfrapb.Ordering_Column_DESC, execinfrapb.Ordering_Column_DESC}, 1112 leftTuples: tuples{{4, 3, 3}, {nil, 2, nil}, {nil, 1, 3}}, 1113 rightTuples: tuples{{2, 3, 1}, {2, nil, 1}, {nil, 1, 3}}, 1114 leftOutCols: []uint32{0, 1, 2}, 1115 rightOutCols: []uint32{0, 1, 2}, 1116 leftEqCols: []uint32{0, 1, 2}, 1117 rightEqCols: []uint32{0, 1, 2}, 1118 expected: tuples{{4, 3, 3, nil, nil, nil}, {nil, nil, nil, 2, 3, 1}, {nil, nil, nil, 2, nil, 1}, {nil, 2, nil, nil, nil, nil}, {nil, 1, 3, nil, nil, nil}, {nil, nil, nil, nil, 1, 3}}, 1119 }, 1120 { 1121 description: "3 equality column FULL OUTER JOIN test with nulls mixed ordering", 1122 joinType: sqlbase.FullOuterJoin, 1123 leftTypes: []*types.T{types.Int, types.Int, types.Int}, 1124 rightTypes: []*types.T{types.Int, types.Int, types.Int}, 1125 leftDirections: []execinfrapb.Ordering_Column_Direction{execinfrapb.Ordering_Column_DESC, execinfrapb.Ordering_Column_DESC, execinfrapb.Ordering_Column_ASC}, 1126 rightDirections: []execinfrapb.Ordering_Column_Direction{execinfrapb.Ordering_Column_ASC, execinfrapb.Ordering_Column_DESC, execinfrapb.Ordering_Column_DESC}, 1127 leftTuples: tuples{{4, 3, 3}, {nil, 2, nil}, {nil, 1, 3}}, 1128 rightTuples: tuples{{2, 3, 1}, {2, nil, 1}, {nil, 1, 3}}, 1129 leftOutCols: []uint32{0, 1, 2}, 1130 rightOutCols: []uint32{0, 1, 2}, 1131 leftEqCols: []uint32{0, 1, 2}, 1132 rightEqCols: []uint32{1, 2, 0}, 1133 expected: tuples{{4, 3, 3, nil, nil, nil}, {nil, nil, nil, 2, 3, 1}, {nil, nil, nil, 2, nil, 1}, {nil, 2, nil, nil, nil, nil}, {nil, 1, 3, nil, nil, nil}, {nil, nil, nil, nil, 1, 3}}, 1134 }, 1135 { 1136 description: "single column DESC with nulls on the right FULL OUTER JOIN", 1137 joinType: sqlbase.FullOuterJoin, 1138 leftTypes: []*types.T{types.Int}, 1139 rightTypes: []*types.T{types.Int}, 1140 leftDirections: []execinfrapb.Ordering_Column_Direction{execinfrapb.Ordering_Column_DESC}, 1141 rightDirections: []execinfrapb.Ordering_Column_Direction{execinfrapb.Ordering_Column_DESC}, 1142 leftTuples: tuples{{1}}, 1143 rightTuples: tuples{{1}, {1}, {1}, {nil}, {nil}, {nil}}, 1144 leftOutCols: []uint32{0}, 1145 rightOutCols: []uint32{0}, 1146 leftEqCols: []uint32{0}, 1147 rightEqCols: []uint32{0}, 1148 expected: tuples{{1, 1}, {1, 1}, {1, 1}, {nil, nil}, {nil, nil}, {nil, nil}}, 1149 }, 1150 { 1151 description: "FULL OUTER JOIN test with nulls and Bytes", 1152 joinType: sqlbase.FullOuterJoin, 1153 leftTypes: []*types.T{types.Int, types.Bytes}, 1154 rightTypes: []*types.T{types.Int, types.Bytes}, 1155 leftTuples: tuples{{nil, "0"}, {1, "10"}, {2, "20"}, {3, nil}, {4, "40"}}, 1156 rightTuples: tuples{{1, nil}, {3, "13"}, {4, nil}}, 1157 leftOutCols: []uint32{0, 1}, 1158 rightOutCols: []uint32{1}, 1159 leftEqCols: []uint32{0}, 1160 rightEqCols: []uint32{0}, 1161 expected: tuples{{nil, "0", nil}, {1, "10", nil}, {2, "20", nil}, {3, nil, "13"}, {4, "40", nil}}, 1162 }, 1163 { 1164 description: "basic LEFT SEMI JOIN test, L and R exhausted at the same time", 1165 joinType: sqlbase.LeftSemiJoin, 1166 leftTypes: []*types.T{types.Int}, 1167 rightTypes: []*types.T{types.Int}, 1168 leftTuples: tuples{{1}, {2}, {3}, {4}, {4}}, 1169 rightTuples: tuples{{-1}, {2}, {3}, {4}, {4}}, 1170 leftOutCols: []uint32{0}, 1171 rightOutCols: []uint32{}, 1172 leftEqCols: []uint32{0}, 1173 rightEqCols: []uint32{0}, 1174 expected: tuples{{2}, {3}, {4}, {4}}, 1175 }, 1176 { 1177 description: "basic LEFT SEMI JOIN test, R exhausted first", 1178 joinType: sqlbase.LeftSemiJoin, 1179 leftTypes: []*types.T{types.Int}, 1180 rightTypes: []*types.T{types.Int}, 1181 leftTuples: tuples{{1}, {1}, {3}, {5}, {6}, {7}}, 1182 rightTuples: tuples{{2}, {3}, {4}}, 1183 leftOutCols: []uint32{0}, 1184 rightOutCols: []uint32{}, 1185 leftEqCols: []uint32{0}, 1186 rightEqCols: []uint32{0}, 1187 expected: tuples{{3}}, 1188 }, 1189 { 1190 description: "basic LEFT SEMI JOIN test, L exhausted first", 1191 joinType: sqlbase.LeftSemiJoin, 1192 leftTypes: []*types.T{types.Int}, 1193 rightTypes: []*types.T{types.Int}, 1194 leftTuples: tuples{{3}, {5}, {6}, {7}}, 1195 rightTuples: tuples{{2}, {3}, {3}, {3}, {4}, {6}, {8}, {9}}, 1196 leftOutCols: []uint32{0}, 1197 rightOutCols: []uint32{}, 1198 leftEqCols: []uint32{0}, 1199 rightEqCols: []uint32{0}, 1200 expected: tuples{{3}, {6}}, 1201 }, 1202 { 1203 description: "multi output column LEFT SEMI JOIN test with nulls", 1204 joinType: sqlbase.LeftSemiJoin, 1205 leftTypes: []*types.T{types.Int, types.Int}, 1206 rightTypes: []*types.T{types.Int, types.Int}, 1207 leftTuples: tuples{{1, 10}, {2, 20}, {3, nil}, {4, 40}}, 1208 rightTuples: tuples{{1, nil}, {3, 13}, {4, 14}}, 1209 leftOutCols: []uint32{0, 1}, 1210 rightOutCols: []uint32{}, 1211 leftEqCols: []uint32{0}, 1212 rightEqCols: []uint32{0}, 1213 expected: tuples{{1, 10}, {3, nil}, {4, 40}}, 1214 }, 1215 { 1216 description: "null in equality column LEFT SEMI JOIN", 1217 joinType: sqlbase.LeftSemiJoin, 1218 leftTypes: []*types.T{types.Int}, 1219 rightTypes: []*types.T{types.Int, types.Int}, 1220 leftTuples: tuples{{nil}, {nil}, {1}, {3}}, 1221 rightTuples: tuples{{nil, 1}, {1, 1}, {2, 2}, {3, 3}}, 1222 leftOutCols: []uint32{0}, 1223 rightOutCols: []uint32{}, 1224 leftEqCols: []uint32{0}, 1225 rightEqCols: []uint32{0}, 1226 expected: tuples{{1}, {3}}, 1227 }, 1228 { 1229 description: "multi equality column LEFT SEMI JOIN test with nulls", 1230 joinType: sqlbase.LeftSemiJoin, 1231 leftTypes: []*types.T{types.Int, types.Int}, 1232 rightTypes: []*types.T{types.Int, types.Int}, 1233 leftTuples: tuples{{nil, nil}, {nil, 10}, {1, nil}, {1, 10}, {2, 20}, {4, 40}}, 1234 rightTuples: tuples{{nil, nil}, {nil, 10}, {1, nil}, {1, nil}, {2, 20}, {3, 30}}, 1235 leftOutCols: []uint32{0, 1}, 1236 rightOutCols: []uint32{}, 1237 leftEqCols: []uint32{0, 1}, 1238 rightEqCols: []uint32{0, 1}, 1239 expected: tuples{{2, 20}}, 1240 }, 1241 { 1242 description: "multi equality column (long runs on left) LEFT SEMI JOIN test with nulls", 1243 joinType: sqlbase.LeftSemiJoin, 1244 leftTypes: []*types.T{types.Int, types.Int}, 1245 rightTypes: []*types.T{types.Int, types.Int}, 1246 leftTuples: tuples{{1, 9}, {1, 10}, {1, 10}, {1, 11}, {1, 11}, {1, 11}, {2, 20}, {2, 20}, {2, 21}, {2, 22}, {2, 22}}, 1247 rightTuples: tuples{{1, 8}, {1, 11}, {1, 11}, {2, 21}, {2, 23}}, 1248 leftOutCols: []uint32{0, 1}, 1249 rightOutCols: []uint32{}, 1250 leftEqCols: []uint32{0, 1}, 1251 rightEqCols: []uint32{0, 1}, 1252 expected: tuples{{1, 11}, {1, 11}, {1, 11}, {2, 21}}, 1253 }, 1254 { 1255 description: "3 equality column LEFT SEMI JOIN test with nulls DESC ordering", 1256 joinType: sqlbase.LeftSemiJoin, 1257 leftTypes: []*types.T{types.Int, types.Int, types.Int}, 1258 rightTypes: []*types.T{types.Int, types.Int, types.Int}, 1259 leftDirections: []execinfrapb.Ordering_Column_Direction{execinfrapb.Ordering_Column_DESC, execinfrapb.Ordering_Column_DESC, execinfrapb.Ordering_Column_DESC}, 1260 rightDirections: []execinfrapb.Ordering_Column_Direction{execinfrapb.Ordering_Column_DESC, execinfrapb.Ordering_Column_DESC, execinfrapb.Ordering_Column_DESC}, 1261 leftTuples: tuples{{2, 3, 1}, {2, nil, 1}, {nil, 1, 3}}, 1262 rightTuples: tuples{{4, 3, 3}, {nil, 2, nil}, {nil, 1, 3}}, 1263 leftOutCols: []uint32{0, 1, 2}, 1264 rightOutCols: []uint32{}, 1265 leftEqCols: []uint32{0, 1, 2}, 1266 rightEqCols: []uint32{0, 1, 2}, 1267 expected: tuples{}, 1268 // The expected output here is empty, so will it be during the all nulls 1269 // injection, so we want to skip that. 1270 skipAllNullsInjection: true, 1271 }, 1272 { 1273 description: "3 equality column LEFT SEMI JOIN test with nulls mixed ordering", 1274 joinType: sqlbase.LeftSemiJoin, 1275 leftTypes: []*types.T{types.Int, types.Int, types.Int}, 1276 rightTypes: []*types.T{types.Int, types.Int, types.Int}, 1277 leftDirections: []execinfrapb.Ordering_Column_Direction{execinfrapb.Ordering_Column_DESC, execinfrapb.Ordering_Column_DESC, execinfrapb.Ordering_Column_ASC}, 1278 rightDirections: []execinfrapb.Ordering_Column_Direction{execinfrapb.Ordering_Column_ASC, execinfrapb.Ordering_Column_DESC, execinfrapb.Ordering_Column_DESC}, 1279 leftTuples: tuples{{2, 3, 1}, {2, nil, 1}, {nil, 1, 3}}, 1280 rightTuples: tuples{{4, 3, 3}, {nil, 2, nil}, {nil, 1, 3}}, 1281 leftOutCols: []uint32{0, 1, 2}, 1282 rightOutCols: []uint32{}, 1283 leftEqCols: []uint32{0, 1, 2}, 1284 rightEqCols: []uint32{1, 2, 0}, 1285 expected: tuples{}, 1286 // The expected output here is empty, so will it be during the all nulls 1287 // injection, so we want to skip that. 1288 skipAllNullsInjection: true, 1289 }, 1290 { 1291 description: "single column DESC with nulls on the left LEFT SEMI JOIN", 1292 joinType: sqlbase.LeftSemiJoin, 1293 leftTypes: []*types.T{types.Int}, 1294 rightTypes: []*types.T{types.Int}, 1295 leftDirections: []execinfrapb.Ordering_Column_Direction{execinfrapb.Ordering_Column_DESC}, 1296 rightDirections: []execinfrapb.Ordering_Column_Direction{execinfrapb.Ordering_Column_DESC}, 1297 leftTuples: tuples{{1}, {1}, {1}, {nil}, {nil}, {nil}}, 1298 rightTuples: tuples{{1}}, 1299 leftOutCols: []uint32{0}, 1300 rightOutCols: []uint32{}, 1301 leftEqCols: []uint32{0}, 1302 rightEqCols: []uint32{0}, 1303 expected: tuples{{1}, {1}, {1}}, 1304 }, 1305 { 1306 description: "basic LEFT ANTI JOIN test, L and R exhausted at the same time", 1307 joinType: sqlbase.LeftAntiJoin, 1308 leftTypes: []*types.T{types.Int}, 1309 rightTypes: []*types.T{types.Int}, 1310 leftTuples: tuples{{1}, {2}, {3}, {4}, {4}}, 1311 rightTuples: tuples{{-1}, {2}, {4}, {4}}, 1312 leftOutCols: []uint32{0}, 1313 rightOutCols: []uint32{}, 1314 leftEqCols: []uint32{0}, 1315 rightEqCols: []uint32{0}, 1316 expected: tuples{{1}, {3}}, 1317 }, 1318 { 1319 description: "basic LEFT ANTI JOIN test, R exhausted first", 1320 joinType: sqlbase.LeftAntiJoin, 1321 leftTypes: []*types.T{types.Int}, 1322 rightTypes: []*types.T{types.Int}, 1323 leftTuples: tuples{{1}, {1}, {3}, {5}, {6}, {7}}, 1324 rightTuples: tuples{{2}, {3}, {4}}, 1325 leftOutCols: []uint32{0}, 1326 rightOutCols: []uint32{}, 1327 leftEqCols: []uint32{0}, 1328 rightEqCols: []uint32{0}, 1329 expected: tuples{{1}, {1}, {5}, {6}, {7}}, 1330 }, 1331 { 1332 description: "basic LEFT ANTI JOIN test, L exhausted first", 1333 joinType: sqlbase.LeftAntiJoin, 1334 leftTypes: []*types.T{types.Int}, 1335 rightTypes: []*types.T{types.Int}, 1336 leftTuples: tuples{{3}, {5}, {6}, {7}}, 1337 rightTuples: tuples{{2}, {3}, {3}, {3}, {4}, {6}, {8}, {9}}, 1338 leftOutCols: []uint32{0}, 1339 rightOutCols: []uint32{}, 1340 leftEqCols: []uint32{0}, 1341 rightEqCols: []uint32{0}, 1342 expected: tuples{{5}, {7}}, 1343 }, 1344 { 1345 description: "multi output column LEFT ANTI JOIN test with nulls", 1346 joinType: sqlbase.LeftAntiJoin, 1347 leftTypes: []*types.T{types.Int, types.Int}, 1348 rightTypes: []*types.T{types.Int, types.Int}, 1349 leftTuples: tuples{{1, 10}, {2, 20}, {3, nil}, {4, 40}}, 1350 rightTuples: tuples{{1, nil}, {3, 13}, {4, 14}}, 1351 leftOutCols: []uint32{0, 1}, 1352 rightOutCols: []uint32{}, 1353 leftEqCols: []uint32{0}, 1354 rightEqCols: []uint32{0}, 1355 expected: tuples{{2, 20}}, 1356 }, 1357 { 1358 description: "null in equality column LEFT ANTI JOIN", 1359 joinType: sqlbase.LeftAntiJoin, 1360 leftTypes: []*types.T{types.Int}, 1361 rightTypes: []*types.T{types.Int, types.Int}, 1362 leftTuples: tuples{{nil}, {nil}, {1}, {3}}, 1363 rightTuples: tuples{{nil, 1}, {1, 1}, {2, 2}, {3, 3}}, 1364 leftOutCols: []uint32{0}, 1365 rightOutCols: []uint32{}, 1366 leftEqCols: []uint32{0}, 1367 rightEqCols: []uint32{0}, 1368 expected: tuples{{nil}, {nil}}, 1369 }, 1370 { 1371 description: "multi equality column LEFT ANTI JOIN test with nulls", 1372 joinType: sqlbase.LeftAntiJoin, 1373 leftTypes: []*types.T{types.Int, types.Int}, 1374 rightTypes: []*types.T{types.Int, types.Int}, 1375 leftTuples: tuples{{nil, nil}, {nil, 10}, {1, nil}, {1, 10}, {2, 20}, {4, 40}}, 1376 rightTuples: tuples{{nil, nil}, {nil, 10}, {1, nil}, {1, nil}, {2, 20}, {3, 30}}, 1377 leftOutCols: []uint32{0, 1}, 1378 rightOutCols: []uint32{}, 1379 leftEqCols: []uint32{0, 1}, 1380 rightEqCols: []uint32{0, 1}, 1381 expected: tuples{{nil, nil}, {nil, 10}, {1, nil}, {1, 10}, {4, 40}}, 1382 }, 1383 { 1384 description: "multi equality column (long runs on left) LEFT ANTI JOIN test with nulls", 1385 joinType: sqlbase.LeftAntiJoin, 1386 leftTypes: []*types.T{types.Int, types.Int}, 1387 rightTypes: []*types.T{types.Int, types.Int}, 1388 leftTuples: tuples{{1, 9}, {1, 10}, {1, 10}, {1, 11}, {1, 11}, {1, 11}, {2, 20}, {2, 20}, {2, 21}, {2, 22}, {2, 22}}, 1389 rightTuples: tuples{{1, 8}, {1, 11}, {1, 11}, {2, 21}, {2, 23}}, 1390 leftOutCols: []uint32{0, 1}, 1391 rightOutCols: []uint32{}, 1392 leftEqCols: []uint32{0, 1}, 1393 rightEqCols: []uint32{0, 1}, 1394 expected: tuples{{1, 9}, {1, 10}, {1, 10}, {2, 20}, {2, 20}, {2, 22}, {2, 22}}, 1395 }, 1396 { 1397 description: "3 equality column LEFT ANTI JOIN test with nulls DESC ordering", 1398 joinType: sqlbase.LeftAntiJoin, 1399 leftTypes: []*types.T{types.Int, types.Int, types.Int}, 1400 rightTypes: []*types.T{types.Int, types.Int, types.Int}, 1401 leftDirections: []execinfrapb.Ordering_Column_Direction{execinfrapb.Ordering_Column_DESC, execinfrapb.Ordering_Column_DESC, execinfrapb.Ordering_Column_DESC}, 1402 rightDirections: []execinfrapb.Ordering_Column_Direction{execinfrapb.Ordering_Column_DESC, execinfrapb.Ordering_Column_DESC, execinfrapb.Ordering_Column_DESC}, 1403 leftTuples: tuples{{2, 3, 1}, {2, nil, 1}, {nil, 1, 3}}, 1404 rightTuples: tuples{{4, 3, 3}, {nil, 2, nil}, {nil, 1, 3}}, 1405 leftOutCols: []uint32{0, 1, 2}, 1406 rightOutCols: []uint32{}, 1407 leftEqCols: []uint32{0, 1, 2}, 1408 rightEqCols: []uint32{0, 1, 2}, 1409 expected: tuples{{2, 3, 1}, {2, nil, 1}, {nil, 1, 3}}, 1410 }, 1411 { 1412 description: "3 equality column LEFT ANTI JOIN test with nulls mixed ordering", 1413 joinType: sqlbase.LeftAntiJoin, 1414 leftTypes: []*types.T{types.Int, types.Int, types.Int}, 1415 rightTypes: []*types.T{types.Int, types.Int, types.Int}, 1416 leftDirections: []execinfrapb.Ordering_Column_Direction{execinfrapb.Ordering_Column_DESC, execinfrapb.Ordering_Column_DESC, execinfrapb.Ordering_Column_ASC}, 1417 rightDirections: []execinfrapb.Ordering_Column_Direction{execinfrapb.Ordering_Column_ASC, execinfrapb.Ordering_Column_DESC, execinfrapb.Ordering_Column_DESC}, 1418 leftTuples: tuples{{2, 3, 1}, {2, nil, 1}, {nil, 1, 3}}, 1419 rightTuples: tuples{{4, 3, 3}, {nil, 2, nil}, {nil, 1, 3}}, 1420 leftOutCols: []uint32{0, 1, 2}, 1421 rightOutCols: []uint32{}, 1422 leftEqCols: []uint32{0, 1, 2}, 1423 rightEqCols: []uint32{1, 2, 0}, 1424 expected: tuples{{2, 3, 1}, {2, nil, 1}, {nil, 1, 3}}, 1425 }, 1426 { 1427 description: "single column DESC with nulls on the left LEFT ANTI JOIN", 1428 joinType: sqlbase.LeftAntiJoin, 1429 leftTypes: []*types.T{types.Int}, 1430 rightTypes: []*types.T{types.Int}, 1431 leftDirections: []execinfrapb.Ordering_Column_Direction{execinfrapb.Ordering_Column_DESC}, 1432 rightDirections: []execinfrapb.Ordering_Column_Direction{execinfrapb.Ordering_Column_DESC}, 1433 leftTuples: tuples{{1}, {1}, {1}, {nil}, {nil}, {nil}}, 1434 rightTuples: tuples{{1}, {nil}}, 1435 leftOutCols: []uint32{0}, 1436 rightOutCols: []uint32{}, 1437 leftEqCols: []uint32{0}, 1438 rightEqCols: []uint32{0}, 1439 expected: tuples{{nil}, {nil}, {nil}}, 1440 }, 1441 { 1442 description: "INNER JOIN test with ON expression (filter only on left)", 1443 joinType: sqlbase.InnerJoin, 1444 leftTypes: []*types.T{types.Int, types.Int}, 1445 rightTypes: []*types.T{types.Int, types.Int}, 1446 leftTuples: tuples{{nil, 0}, {1, 10}, {2, 20}, {3, nil}, {4, 40}}, 1447 rightTuples: tuples{{1, nil}, {3, 13}, {4, 14}}, 1448 leftOutCols: []uint32{0, 1}, 1449 rightOutCols: []uint32{}, 1450 leftEqCols: []uint32{0}, 1451 rightEqCols: []uint32{0}, 1452 onExpr: execinfrapb.Expression{Expr: "@1 < 4"}, 1453 expected: tuples{{1, 10}, {3, nil}}, 1454 }, 1455 { 1456 description: "INNER JOIN test with ON expression (filter only on right)", 1457 joinType: sqlbase.InnerJoin, 1458 leftTypes: []*types.T{types.Int, types.Int}, 1459 rightTypes: []*types.T{types.Int, types.Int}, 1460 leftTuples: tuples{{nil, 0}, {1, 10}, {2, 20}, {3, nil}, {4, 40}}, 1461 rightTuples: tuples{{1, nil}, {3, 13}, {4, 14}}, 1462 leftOutCols: []uint32{0, 1}, 1463 rightOutCols: []uint32{}, 1464 leftEqCols: []uint32{0}, 1465 rightEqCols: []uint32{0}, 1466 onExpr: execinfrapb.Expression{Expr: "@4 < 14"}, 1467 expected: tuples{{3, nil}}, 1468 }, 1469 { 1470 description: "INNER JOIN test with ON expression (filter on both)", 1471 joinType: sqlbase.InnerJoin, 1472 leftTypes: []*types.T{types.Int, types.Int}, 1473 rightTypes: []*types.T{types.Int, types.Int}, 1474 leftTuples: tuples{{nil, 0}, {1, 10}, {2, 20}, {3, nil}, {4, 40}}, 1475 rightTuples: tuples{{1, nil}, {3, 13}, {4, 14}}, 1476 leftOutCols: []uint32{0, 1}, 1477 rightOutCols: []uint32{}, 1478 leftEqCols: []uint32{0}, 1479 rightEqCols: []uint32{0}, 1480 onExpr: execinfrapb.Expression{Expr: "@2 + @3 < 50"}, 1481 expected: tuples{{1, 10}, {4, 40}}, 1482 }, 1483 { 1484 description: "INTERSECT ALL join basic", 1485 joinType: sqlbase.IntersectAllJoin, 1486 leftTypes: []*types.T{types.Int}, 1487 rightTypes: []*types.T{types.Int}, 1488 leftTuples: tuples{{1}, {1}, {2}, {2}, {3}}, 1489 rightTuples: tuples{{1}, {2}, {2}, {3}, {3}, {3}}, 1490 leftOutCols: []uint32{0}, 1491 rightOutCols: []uint32{}, 1492 leftEqCols: []uint32{0}, 1493 rightEqCols: []uint32{0}, 1494 expected: tuples{{1}, {2}, {2}, {3}}, 1495 }, 1496 { 1497 description: "INTERSECT ALL join with mixed ordering with NULLs", 1498 joinType: sqlbase.IntersectAllJoin, 1499 leftTypes: []*types.T{types.Int, types.Int}, 1500 rightTypes: []*types.T{types.Int, types.Int}, 1501 leftTuples: tuples{{4, nil}, {4, 1}, {1, nil}, {1, 2}, {0, 2}, {0, 3}, {nil, 1}, {nil, 2}, {nil, 2}, {nil, 3}}, 1502 rightTuples: tuples{{3, 2}, {2, 1}, {2, 2}, {2, 3}, {1, nil}, {1, 1}, {1, 1}, {0, 1}, {0, 2}, {nil, 2}}, 1503 leftOutCols: []uint32{0, 1}, 1504 rightOutCols: []uint32{}, 1505 leftEqCols: []uint32{0, 1}, 1506 leftDirections: []execinfrapb.Ordering_Column_Direction{ 1507 execinfrapb.Ordering_Column_DESC, execinfrapb.Ordering_Column_ASC, 1508 }, 1509 rightEqCols: []uint32{0, 1}, 1510 rightDirections: []execinfrapb.Ordering_Column_Direction{ 1511 execinfrapb.Ordering_Column_DESC, execinfrapb.Ordering_Column_ASC, 1512 }, 1513 expected: tuples{{1, nil}, {0, 2}, {nil, 2}}, 1514 }, 1515 { 1516 description: "INTERSECT ALL join with mixed ordering with NULLs on the left", 1517 joinType: sqlbase.IntersectAllJoin, 1518 leftTypes: []*types.T{types.Int, types.Int}, 1519 rightTypes: []*types.T{types.Int, types.Int}, 1520 leftTuples: tuples{{nil, 3}, {nil, nil}, {9, 6}, {9, 0}, {9, nil}}, 1521 rightTuples: tuples{{0, 5}, {0, 4}, {8, 8}, {8, 6}, {9, 0}}, 1522 leftOutCols: []uint32{0, 1}, 1523 rightOutCols: []uint32{}, 1524 leftEqCols: []uint32{0, 1}, 1525 leftDirections: []execinfrapb.Ordering_Column_Direction{ 1526 execinfrapb.Ordering_Column_ASC, execinfrapb.Ordering_Column_DESC, 1527 }, 1528 rightEqCols: []uint32{0, 1}, 1529 rightDirections: []execinfrapb.Ordering_Column_Direction{ 1530 execinfrapb.Ordering_Column_ASC, execinfrapb.Ordering_Column_DESC, 1531 }, 1532 expected: tuples{{9, 0}}, 1533 }, 1534 { 1535 description: "INTERSECT ALL join on booleans", 1536 joinType: sqlbase.IntersectAllJoin, 1537 leftTypes: []*types.T{types.Bool}, 1538 rightTypes: []*types.T{types.Bool}, 1539 leftTuples: tuples{{nil}, {nil}, {false}, {false}, {true}, {true}, {true}}, 1540 rightTuples: tuples{{nil}, {false}, {false}, {false}, {false}, {true}}, 1541 leftOutCols: []uint32{0}, 1542 rightOutCols: []uint32{}, 1543 leftEqCols: []uint32{0}, 1544 rightEqCols: []uint32{0}, 1545 expected: tuples{{nil}, {false}, {false}, {true}}, 1546 }, 1547 { 1548 description: "EXCEPT ALL join basic", 1549 joinType: sqlbase.ExceptAllJoin, 1550 leftTypes: []*types.T{types.Int}, 1551 rightTypes: []*types.T{types.Int}, 1552 leftTuples: tuples{{1}, {1}, {2}, {2}, {2}, {3}, {3}}, 1553 rightTuples: tuples{{1}, {2}, {3}, {3}, {3}}, 1554 leftOutCols: []uint32{0}, 1555 rightOutCols: []uint32{}, 1556 leftEqCols: []uint32{0}, 1557 rightEqCols: []uint32{0}, 1558 expected: tuples{{1}, {2}, {2}}, 1559 }, 1560 { 1561 description: "EXCEPT ALL join with mixed ordering with NULLs", 1562 joinType: sqlbase.ExceptAllJoin, 1563 leftTypes: []*types.T{types.Int, types.Int}, 1564 rightTypes: []*types.T{types.Int, types.Int}, 1565 leftTuples: tuples{{4, nil}, {4, 1}, {1, nil}, {1, 2}, {0, 2}, {0, 3}, {nil, 1}, {nil, 2}, {nil, 2}, {nil, 3}}, 1566 rightTuples: tuples{{3, 2}, {2, 1}, {2, 2}, {2, 3}, {1, nil}, {1, 1}, {1, 1}, {0, 1}, {0, 2}, {nil, 2}}, 1567 leftOutCols: []uint32{0, 1}, 1568 rightOutCols: []uint32{}, 1569 leftEqCols: []uint32{0, 1}, 1570 leftDirections: []execinfrapb.Ordering_Column_Direction{ 1571 execinfrapb.Ordering_Column_DESC, execinfrapb.Ordering_Column_ASC, 1572 }, 1573 rightEqCols: []uint32{0, 1}, 1574 rightDirections: []execinfrapb.Ordering_Column_Direction{ 1575 execinfrapb.Ordering_Column_DESC, execinfrapb.Ordering_Column_ASC, 1576 }, 1577 expected: tuples{{4, nil}, {4, 1}, {1, 2}, {0, 3}, {nil, 1}, {nil, 2}, {nil, 3}}, 1578 }, 1579 { 1580 description: "EXCEPT ALL join with mixed ordering with NULLs on the left", 1581 joinType: sqlbase.ExceptAllJoin, 1582 leftTypes: []*types.T{types.Int, types.Int}, 1583 rightTypes: []*types.T{types.Int, types.Int}, 1584 leftTuples: tuples{{nil, 3}, {nil, nil}, {9, 6}, {9, 0}, {9, nil}}, 1585 rightTuples: tuples{{0, 5}, {0, 4}, {8, 8}, {8, 6}, {9, 0}}, 1586 leftOutCols: []uint32{0, 1}, 1587 rightOutCols: []uint32{}, 1588 leftEqCols: []uint32{0, 1}, 1589 leftDirections: []execinfrapb.Ordering_Column_Direction{ 1590 execinfrapb.Ordering_Column_ASC, execinfrapb.Ordering_Column_DESC, 1591 }, 1592 rightEqCols: []uint32{0, 1}, 1593 rightDirections: []execinfrapb.Ordering_Column_Direction{ 1594 execinfrapb.Ordering_Column_ASC, execinfrapb.Ordering_Column_DESC, 1595 }, 1596 expected: tuples{{nil, 3}, {nil, nil}, {9, 6}, {9, nil}}, 1597 }, 1598 { 1599 description: "EXCEPT ALL join on booleans", 1600 joinType: sqlbase.ExceptAllJoin, 1601 leftTypes: []*types.T{types.Bool}, 1602 rightTypes: []*types.T{types.Bool}, 1603 leftTuples: tuples{{nil}, {nil}, {false}, {false}, {true}, {true}, {true}}, 1604 rightTuples: tuples{{nil}, {false}, {false}, {false}, {false}, {true}}, 1605 leftOutCols: []uint32{0}, 1606 rightOutCols: []uint32{}, 1607 leftEqCols: []uint32{0}, 1608 rightEqCols: []uint32{0}, 1609 expected: tuples{{nil}, {true}, {true}}, 1610 }, 1611 } 1612 1613 func TestMergeJoiner(t *testing.T) { 1614 defer leaktest.AfterTest(t)() 1615 ctx := context.Background() 1616 st := cluster.MakeTestingClusterSettings() 1617 evalCtx := tree.MakeTestingEvalContext(st) 1618 defer evalCtx.Stop(ctx) 1619 flowCtx := &execinfra.FlowCtx{ 1620 EvalCtx: &evalCtx, 1621 Cfg: &execinfra.ServerConfig{ 1622 Settings: st, 1623 DiskMonitor: testDiskMonitor, 1624 }, 1625 } 1626 queueCfg, cleanup := colcontainerutils.NewTestingDiskQueueCfg(t, true /* inMem */) 1627 defer cleanup() 1628 var ( 1629 accounts []*mon.BoundAccount 1630 monitors []*mon.BytesMonitor 1631 ) 1632 for _, tc := range mjTestCases { 1633 for _, tc := range tc.mutateTypes() { 1634 tc.init() 1635 1636 // We use a custom verifier function so that we can get the merge join op 1637 // to use a custom output batch size per test, to exercise more cases. 1638 var mergeJoinVerifier verifierFn = func(output *opTestOutput) error { 1639 if mj, ok := output.input.(variableOutputBatchSizeInitializer); ok { 1640 mj.initWithOutputBatchSize(tc.outputBatchSize) 1641 } else { 1642 // When we have an inner join with ON expression, a filter operator 1643 // will be put on top of the merge join, so to make life easier, we'll 1644 // just ignore the requested output batch size. 1645 output.input.Init() 1646 } 1647 verify := output.Verify 1648 if _, isFullOuter := output.input.(*mergeJoinFullOuterOp); isFullOuter { 1649 // FULL OUTER JOIN doesn't guarantee any ordering on its output (since 1650 // it is ambiguous), so we're comparing the outputs as sets. 1651 verify = output.VerifyAnyOrder 1652 } 1653 1654 return verify() 1655 } 1656 1657 var runner testRunner 1658 if tc.skipAllNullsInjection { 1659 // We're omitting all nulls injection test. See comments for each such 1660 // test case. 1661 runner = runTestsWithoutAllNullsInjection 1662 } else { 1663 runner = runTestsWithTyps 1664 } 1665 // We test all cases with the default memory limit (regular scenario) and a 1666 // limit of 1 byte (to force the buffered groups to spill to disk). 1667 for _, memoryLimit := range []int64{1, defaultMemoryLimit} { 1668 t.Run(fmt.Sprintf("MemoryLimit=%s/%s", humanizeutil.IBytes(memoryLimit), tc.description), func(t *testing.T) { 1669 runner(t, []tuples{tc.leftTuples, tc.rightTuples}, 1670 [][]*types.T{tc.leftTypes, tc.rightTypes}, 1671 tc.expected, mergeJoinVerifier, 1672 func(input []colexecbase.Operator) (colexecbase.Operator, error) { 1673 spec := createSpecForMergeJoiner(tc) 1674 args := NewColOperatorArgs{ 1675 Spec: spec, 1676 Inputs: input, 1677 StreamingMemAccount: testMemAcc, 1678 DiskQueueCfg: queueCfg, 1679 FDSemaphore: colexecbase.NewTestingSemaphore(mjFDLimit), 1680 } 1681 args.TestingKnobs.UseStreamingMemAccountForBuffering = true 1682 flowCtx.Cfg.TestingKnobs.MemoryLimitBytes = memoryLimit 1683 result, err := NewColOperator(ctx, flowCtx, args) 1684 if err != nil { 1685 return nil, err 1686 } 1687 accounts = append(accounts, result.OpAccounts...) 1688 monitors = append(monitors, result.OpMonitors...) 1689 return result.Op, nil 1690 }) 1691 }) 1692 } 1693 } 1694 } 1695 for _, acc := range accounts { 1696 acc.Close(ctx) 1697 } 1698 for _, mon := range monitors { 1699 mon.Stop(ctx) 1700 } 1701 } 1702 1703 // Merge joiner will be using two spillingQueues, and each of them will use 1704 // 2 file descriptors. 1705 const mjFDLimit = 4 1706 1707 // TestFullOuterMergeJoinWithMaximumNumberOfGroups will create two input 1708 // sources such that the left one contains rows with even numbers 0, 2, 4, ... 1709 // while the right contains one rows with odd numbers 1, 3, 5, ... The test 1710 // will perform FULL OUTER JOIN. Such setup will create the maximum number of 1711 // groups per batch. 1712 func TestFullOuterMergeJoinWithMaximumNumberOfGroups(t *testing.T) { 1713 defer leaktest.AfterTest(t)() 1714 ctx := context.Background() 1715 nTuples := coldata.BatchSize() * 4 1716 queueCfg, cleanup := colcontainerutils.NewTestingDiskQueueCfg(t, true /* inMem */) 1717 defer cleanup() 1718 for _, outBatchSize := range []int{1, 16, coldata.BatchSize() - 1, coldata.BatchSize(), coldata.BatchSize() + 1} { 1719 t.Run(fmt.Sprintf("outBatchSize=%d", outBatchSize), 1720 func(t *testing.T) { 1721 typs := []*types.T{types.Int} 1722 colsLeft := []coldata.Vec{testAllocator.NewMemColumn(typs[0], nTuples)} 1723 colsRight := []coldata.Vec{testAllocator.NewMemColumn(typs[0], nTuples)} 1724 groupsLeft := colsLeft[0].Int64() 1725 groupsRight := colsRight[0].Int64() 1726 for i := range groupsLeft { 1727 groupsLeft[i] = int64(i * 2) 1728 groupsRight[i] = int64(i*2 + 1) 1729 } 1730 leftSource := newChunkingBatchSource(typs, colsLeft, nTuples) 1731 rightSource := newChunkingBatchSource(typs, colsRight, nTuples) 1732 a, err := newMergeJoinOp( 1733 testAllocator, defaultMemoryLimit, queueCfg, 1734 colexecbase.NewTestingSemaphore(mjFDLimit), sqlbase.FullOuterJoin, 1735 leftSource, rightSource, typs, typs, 1736 []execinfrapb.Ordering_Column{{ColIdx: 0, Direction: execinfrapb.Ordering_Column_ASC}}, 1737 []execinfrapb.Ordering_Column{{ColIdx: 0, Direction: execinfrapb.Ordering_Column_ASC}}, 1738 testDiskAcc, 1739 ) 1740 if err != nil { 1741 t.Fatal("error in merge join op constructor", err) 1742 } 1743 a.(*mergeJoinFullOuterOp).initWithOutputBatchSize(outBatchSize) 1744 i, count, expVal := 0, 0, int64(0) 1745 for b := a.Next(ctx); b.Length() != 0; b = a.Next(ctx) { 1746 count += b.Length() 1747 leftOutCol := b.ColVec(0).Int64() 1748 leftNulls := b.ColVec(0).Nulls() 1749 rightOutCol := b.ColVec(1).Int64() 1750 rightNulls := b.ColVec(1).Nulls() 1751 for j := 0; j < b.Length(); j++ { 1752 leftVal := leftOutCol[j] 1753 leftNull := leftNulls.NullAt(j) 1754 rightVal := rightOutCol[j] 1755 rightNull := rightNulls.NullAt(j) 1756 if expVal%2 == 0 { 1757 // It is an even-numbered row, so the left value should contain 1758 // expVal and the right value should be NULL. 1759 if leftVal != expVal || leftNull || !rightNull { 1760 t.Fatalf("found left = %d, left NULL? = %t, right NULL? = %t, "+ 1761 "expected left = %d, left NULL? = false, right NULL? = true, idx %d of batch %d", 1762 leftVal, leftNull, rightNull, expVal, j, i) 1763 } 1764 } else { 1765 // It is an odd-numbered row, so the right value should contain 1766 // expVal and the left value should be NULL. 1767 if rightVal != expVal || rightNull || !leftNull { 1768 t.Fatalf("found right = %d, right NULL? = %t, left NULL? = %t, "+ 1769 "expected right = %d, right NULL? = false, left NULL? = true, idx %d of batch %d", 1770 rightVal, rightNull, leftNull, expVal, j, i) 1771 } 1772 } 1773 expVal++ 1774 } 1775 i++ 1776 } 1777 if count != 2*nTuples { 1778 t.Fatalf("found count %d, expected count %d", count, 2*nTuples) 1779 } 1780 }) 1781 } 1782 } 1783 1784 // TestMergeJoinCrossProduct verifies that the merge joiner produces the same 1785 // output as the hash joiner. The test aims at stressing randomly the building 1786 // of cross product (from the buffered groups) in the merge joiner and does it 1787 // by creating input sources such that they contain very big groups (each group 1788 // is about coldata.BatchSize() in size) which will force the merge joiner to 1789 // mostly build from the buffered groups. Join of such input sources results in 1790 // an output quadratic in size, so the test is skipped unless coldata.BatchSize 1791 // is set to relatively small number, but it is ok since we randomize this 1792 // value. 1793 func TestMergeJoinCrossProduct(t *testing.T) { 1794 defer leaktest.AfterTest(t)() 1795 if coldata.BatchSize() > 200 { 1796 t.Skipf("this test is too slow with relatively big batch size") 1797 } 1798 ctx := context.Background() 1799 nTuples := 2*coldata.BatchSize() + 1 1800 queueCfg, cleanup := colcontainerutils.NewTestingDiskQueueCfg(t, true /* inMem */) 1801 defer cleanup() 1802 rng, _ := randutil.NewPseudoRand() 1803 for _, outBatchSize := range []int{1, 17, coldata.BatchSize() - 1, coldata.BatchSize(), coldata.BatchSize() + 1} { 1804 t.Run(fmt.Sprintf("outBatchSize=%d", outBatchSize), 1805 func(t *testing.T) { 1806 typs := []*types.T{types.Int, types.Bytes, types.Decimal} 1807 colsLeft := make([]coldata.Vec, len(typs)) 1808 colsRight := make([]coldata.Vec, len(typs)) 1809 for i, typ := range typs { 1810 colsLeft[i] = testAllocator.NewMemColumn(typ, nTuples) 1811 colsRight[i] = testAllocator.NewMemColumn(typ, nTuples) 1812 } 1813 groupsLeft := colsLeft[0].Int64() 1814 groupsRight := colsRight[0].Int64() 1815 leftGroupIdx, rightGroupIdx := 0, 0 1816 for i := range groupsLeft { 1817 if rng.Float64() < 1.0/float64(coldata.BatchSize()) { 1818 leftGroupIdx++ 1819 } 1820 if rng.Float64() < 1.0/float64(coldata.BatchSize()) { 1821 rightGroupIdx++ 1822 } 1823 groupsLeft[i] = int64(leftGroupIdx) 1824 groupsRight[i] = int64(rightGroupIdx) 1825 } 1826 for i := range typs[1:] { 1827 for _, vecs := range [][]coldata.Vec{colsLeft, colsRight} { 1828 coldatatestutils.RandomVec(coldatatestutils.RandomVecArgs{ 1829 Rand: rng, 1830 Vec: vecs[i+1], 1831 N: nTuples, 1832 NullProbability: nullProbability, 1833 }) 1834 } 1835 } 1836 leftMJSource := newChunkingBatchSource(typs, colsLeft, nTuples) 1837 rightMJSource := newChunkingBatchSource(typs, colsRight, nTuples) 1838 leftHJSource := newChunkingBatchSource(typs, colsLeft, nTuples) 1839 rightHJSource := newChunkingBatchSource(typs, colsRight, nTuples) 1840 mj, err := newMergeJoinOp( 1841 testAllocator, defaultMemoryLimit, queueCfg, 1842 colexecbase.NewTestingSemaphore(mjFDLimit), sqlbase.InnerJoin, 1843 leftMJSource, rightMJSource, typs, typs, 1844 []execinfrapb.Ordering_Column{{ColIdx: 0, Direction: execinfrapb.Ordering_Column_ASC}}, 1845 []execinfrapb.Ordering_Column{{ColIdx: 0, Direction: execinfrapb.Ordering_Column_ASC}}, 1846 testDiskAcc, 1847 ) 1848 if err != nil { 1849 t.Fatal("error in merge join op constructor", err) 1850 } 1851 mj.(*mergeJoinInnerOp).initWithOutputBatchSize(outBatchSize) 1852 hj := newHashJoiner( 1853 testAllocator, hashJoinerSpec{ 1854 joinType: sqlbase.InnerJoin, 1855 left: hashJoinerSourceSpec{ 1856 eqCols: []uint32{0}, sourceTypes: typs, 1857 }, 1858 right: hashJoinerSourceSpec{ 1859 eqCols: []uint32{0}, sourceTypes: typs, 1860 }, 1861 }, leftHJSource, rightHJSource) 1862 hj.Init() 1863 1864 var mjOutputTuples, hjOutputTuples tuples 1865 for b := mj.Next(ctx); b.Length() != 0; b = mj.Next(ctx) { 1866 for i := 0; i < b.Length(); i++ { 1867 mjOutputTuples = append(mjOutputTuples, getTupleFromBatch(b, i)) 1868 } 1869 } 1870 for b := hj.Next(ctx); b.Length() != 0; b = hj.Next(ctx) { 1871 for i := 0; i < b.Length(); i++ { 1872 hjOutputTuples = append(hjOutputTuples, getTupleFromBatch(b, i)) 1873 } 1874 } 1875 err = assertTuplesSetsEqual(hjOutputTuples, mjOutputTuples) 1876 // Note that the error message can be extremely verbose (it 1877 // might contain all output tuples), so we manually check that 1878 // comparing err to nil returns true (if we were to use 1879 // require.NoError, then the error message would be output). 1880 require.True(t, err == nil) 1881 }) 1882 1883 } 1884 } 1885 1886 // TestMergeJoinerMultiBatch creates one long input of a 1:1 join, and keeps 1887 // track of the expected output to make sure the join output is batched 1888 // correctly. 1889 func TestMergeJoinerMultiBatch(t *testing.T) { 1890 defer leaktest.AfterTest(t)() 1891 ctx := context.Background() 1892 queueCfg, cleanup := colcontainerutils.NewTestingDiskQueueCfg(t, true /* inMem */) 1893 defer cleanup() 1894 for _, numInputBatches := range []int{1, 2, 16} { 1895 for _, outBatchSize := range []int{1, 16, coldata.BatchSize()} { 1896 t.Run(fmt.Sprintf("numInputBatches=%d", numInputBatches), 1897 func(t *testing.T) { 1898 nTuples := coldata.BatchSize() * numInputBatches 1899 typs := []*types.T{types.Int} 1900 cols := []coldata.Vec{testAllocator.NewMemColumn(typs[0], nTuples)} 1901 groups := cols[0].Int64() 1902 for i := range groups { 1903 groups[i] = int64(i) 1904 } 1905 1906 leftSource := newChunkingBatchSource(typs, cols, nTuples) 1907 rightSource := newChunkingBatchSource(typs, cols, nTuples) 1908 1909 a, err := newMergeJoinOp( 1910 testAllocator, defaultMemoryLimit, 1911 queueCfg, colexecbase.NewTestingSemaphore(mjFDLimit), sqlbase.InnerJoin, 1912 leftSource, rightSource, typs, typs, 1913 []execinfrapb.Ordering_Column{{ColIdx: 0, Direction: execinfrapb.Ordering_Column_ASC}}, 1914 []execinfrapb.Ordering_Column{{ColIdx: 0, Direction: execinfrapb.Ordering_Column_ASC}}, 1915 testDiskAcc, 1916 ) 1917 if err != nil { 1918 t.Fatal("error in merge join op constructor", err) 1919 } 1920 1921 a.(*mergeJoinInnerOp).initWithOutputBatchSize(outBatchSize) 1922 1923 i := 0 1924 count := 0 1925 // Keep track of the last comparison value. 1926 expVal := int64(0) 1927 for b := a.Next(ctx); b.Length() != 0; b = a.Next(ctx) { 1928 count += b.Length() 1929 outCol := b.ColVec(0).Int64() 1930 for j := int64(0); j < int64(b.Length()); j++ { 1931 outVal := outCol[j] 1932 if outVal != expVal { 1933 t.Fatalf("found val %d, expected %d, idx %d of batch %d", 1934 outVal, expVal, j, i) 1935 } 1936 expVal++ 1937 } 1938 i++ 1939 } 1940 if count != nTuples { 1941 t.Fatalf("found count %d, expected count %d", count, nTuples) 1942 } 1943 }) 1944 } 1945 } 1946 } 1947 1948 // TestMergeJoinerMultiBatchRuns creates one long input of a n:n join, and 1949 // keeps track of the expected count to make sure the join output is batched 1950 // correctly. 1951 func TestMergeJoinerMultiBatchRuns(t *testing.T) { 1952 defer leaktest.AfterTest(t)() 1953 ctx := context.Background() 1954 queueCfg, cleanup := colcontainerutils.NewTestingDiskQueueCfg(t, true /* inMem */) 1955 defer cleanup() 1956 for _, groupSize := range []int{coldata.BatchSize() / 8, coldata.BatchSize() / 4, coldata.BatchSize() / 2} { 1957 if groupSize == 0 { 1958 // We might be varying coldata.BatchSize() so that when it is divided by 1959 // 4, groupSize is 0. We want to skip such configuration. 1960 continue 1961 } 1962 for _, numInputBatches := range []int{1, 2, 16} { 1963 t.Run(fmt.Sprintf("groupSize=%d/numInputBatches=%d", groupSize, numInputBatches), 1964 func(t *testing.T) { 1965 nTuples := coldata.BatchSize() * numInputBatches 1966 // There will be nTuples/groupSize "full" groups - i.e. groups of 1967 // groupSize. Each of these "full" groups will produce groupSize^2 1968 // tuples. The last group might be not full and will consist of 1969 // nTuples % groupSize tuples. That group will produce 1970 // lastGroupSize^2 tuples. 1971 // Note that the math will still be correct in case when nTuples is 1972 // divisible by groupSize - all the groups will be full and "last" 1973 // group will be of size 0. 1974 lastGroupSize := nTuples % groupSize 1975 expCount := nTuples/groupSize*(groupSize*groupSize) + lastGroupSize*lastGroupSize 1976 typs := []*types.T{types.Int, types.Int} 1977 cols := []coldata.Vec{ 1978 testAllocator.NewMemColumn(typs[0], nTuples), 1979 testAllocator.NewMemColumn(typs[1], nTuples), 1980 } 1981 for i := range cols[0].Int64() { 1982 cols[0].Int64()[i] = int64(i / groupSize) 1983 cols[1].Int64()[i] = int64(i / groupSize) 1984 } 1985 1986 leftSource := newChunkingBatchSource(typs, cols, nTuples) 1987 rightSource := newChunkingBatchSource(typs, cols, nTuples) 1988 1989 a, err := newMergeJoinOp( 1990 testAllocator, defaultMemoryLimit, 1991 queueCfg, colexecbase.NewTestingSemaphore(mjFDLimit), sqlbase.InnerJoin, 1992 leftSource, rightSource, typs, typs, 1993 []execinfrapb.Ordering_Column{{ColIdx: 0, Direction: execinfrapb.Ordering_Column_ASC}, {ColIdx: 1, Direction: execinfrapb.Ordering_Column_ASC}}, 1994 []execinfrapb.Ordering_Column{{ColIdx: 0, Direction: execinfrapb.Ordering_Column_ASC}, {ColIdx: 1, Direction: execinfrapb.Ordering_Column_ASC}}, 1995 testDiskAcc, 1996 ) 1997 if err != nil { 1998 t.Fatal("error in merge join op constructor", err) 1999 } 2000 2001 a.(*mergeJoinInnerOp).Init() 2002 2003 i := 0 2004 count := 0 2005 // Keep track of the last comparison value. 2006 lastVal := int64(0) 2007 for b := a.Next(ctx); b.Length() != 0; b = a.Next(ctx) { 2008 count += b.Length() 2009 outCol := b.ColVec(0).Int64() 2010 for j := int64(0); j < int64(b.Length()); j++ { 2011 outVal := outCol[j] 2012 expVal := lastVal / int64(groupSize*groupSize) 2013 if outVal != expVal { 2014 t.Fatalf("found val %d, expected %d, idx %d of batch %d", 2015 outVal, expVal, j, i) 2016 } 2017 lastVal++ 2018 } 2019 i++ 2020 } 2021 2022 if count != expCount { 2023 t.Fatalf("found count %d, expected count %d", 2024 count, expCount) 2025 } 2026 }) 2027 } 2028 } 2029 } 2030 2031 func min(a, b int) int { 2032 if a < b { 2033 return a 2034 } 2035 return b 2036 } 2037 2038 type expectedGroup struct { 2039 val int64 2040 cardinality int 2041 } 2042 2043 func newBatchesOfRandIntRows( 2044 nTuples int, maxRunLength int64, skipValues bool, randomIncrement int64, 2045 ) ([]coldata.Vec, []coldata.Vec, []expectedGroup) { 2046 rng, _ := randutil.NewPseudoRand() 2047 lCols := []coldata.Vec{testAllocator.NewMemColumn(types.Int, nTuples)} 2048 lCol := lCols[0].Int64() 2049 rCols := []coldata.Vec{testAllocator.NewMemColumn(types.Int, nTuples)} 2050 rCol := rCols[0].Int64() 2051 exp := make([]expectedGroup, nTuples) 2052 val := int64(0) 2053 lIdx, rIdx := 0, 0 2054 i := 0 2055 for lIdx < nTuples && rIdx < nTuples { 2056 // Randomly increment the value to write to the group. 2057 val += 1 + randomIncrement*rng.Int63n(256) 2058 // Determine whether or not to create a group. 2059 if skipValues && rng.Int63n(4) == 0 { 2060 lCol[lIdx] = val 2061 lIdx++ 2062 // Randomly increment the value to write to the group. 2063 val += 1 + rng.Int63n(16) 2064 rCol[rIdx] = val 2065 rIdx++ 2066 } else { 2067 lGroupSize := min(int(rng.Int63n(maxRunLength)+1), nTuples-lIdx) 2068 rGroupSize := min(int(rng.Int63n(maxRunLength)+1), nTuples-rIdx) 2069 2070 for j := 0; j < lGroupSize; j++ { 2071 lCol[lIdx] = val 2072 lIdx++ 2073 } 2074 2075 for j := 0; j < rGroupSize; j++ { 2076 rCol[rIdx] = val 2077 rIdx++ 2078 } 2079 2080 exp[i] = expectedGroup{val, lGroupSize * rGroupSize} 2081 i++ 2082 } 2083 } 2084 2085 if lIdx < nTuples { 2086 for lIdx < nTuples { 2087 lCol[lIdx] = val + 1 2088 lIdx++ 2089 } 2090 } 2091 2092 if rIdx < nTuples { 2093 for rIdx < nTuples { 2094 rCol[rIdx] = val + 1 2095 rIdx++ 2096 } 2097 } 2098 2099 return lCols, rCols, exp 2100 } 2101 2102 func TestMergeJoinerRandomized(t *testing.T) { 2103 defer leaktest.AfterTest(t)() 2104 ctx := context.Background() 2105 queueCfg, cleanup := colcontainerutils.NewTestingDiskQueueCfg(t, true /* inMem */) 2106 defer cleanup() 2107 for _, numInputBatches := range []int{1, 2, 16, 256} { 2108 for _, maxRunLength := range []int64{2, 3, 100} { 2109 for _, skipValues := range []bool{false, true} { 2110 for _, randomIncrement := range []int64{0, 1} { 2111 t.Run(fmt.Sprintf("numInputBatches=%d/maxRunLength=%d/skipValues=%t/randomIncrement=%d", numInputBatches, maxRunLength, skipValues, randomIncrement), 2112 func(t *testing.T) { 2113 nTuples := coldata.BatchSize() * numInputBatches 2114 typs := []*types.T{types.Int} 2115 lCols, rCols, exp := newBatchesOfRandIntRows(nTuples, maxRunLength, skipValues, randomIncrement) 2116 leftSource := newChunkingBatchSource(typs, lCols, nTuples) 2117 rightSource := newChunkingBatchSource(typs, rCols, nTuples) 2118 2119 a, err := newMergeJoinOp( 2120 testAllocator, defaultMemoryLimit, 2121 queueCfg, colexecbase.NewTestingSemaphore(mjFDLimit), sqlbase.InnerJoin, 2122 leftSource, rightSource, typs, typs, 2123 []execinfrapb.Ordering_Column{{ColIdx: 0, Direction: execinfrapb.Ordering_Column_ASC}}, 2124 []execinfrapb.Ordering_Column{{ColIdx: 0, Direction: execinfrapb.Ordering_Column_ASC}}, 2125 testDiskAcc, 2126 ) 2127 2128 if err != nil { 2129 t.Fatal("error in merge join op constructor", err) 2130 } 2131 2132 a.(*mergeJoinInnerOp).Init() 2133 2134 i := 0 2135 count := 0 2136 cpIdx := 0 2137 for b := a.Next(ctx); b.Length() != 0; b = a.Next(ctx) { 2138 count += b.Length() 2139 outCol := b.ColVec(0).Int64() 2140 for j := 0; j < b.Length(); j++ { 2141 outVal := outCol[j] 2142 2143 if exp[cpIdx].cardinality == 0 { 2144 cpIdx++ 2145 } 2146 expVal := exp[cpIdx].val 2147 exp[cpIdx].cardinality-- 2148 if expVal != outVal { 2149 t.Fatalf("found val %d, expected %d, idx %d of batch %d", 2150 outVal, expVal, j, i) 2151 } 2152 } 2153 i++ 2154 } 2155 }) 2156 } 2157 } 2158 } 2159 } 2160 } 2161 2162 func newBatchOfIntRows(nCols int, batch coldata.Batch) coldata.Batch { 2163 for colIdx := 0; colIdx < nCols; colIdx++ { 2164 col := batch.ColVec(colIdx).Int64() 2165 for i := 0; i < coldata.BatchSize(); i++ { 2166 col[i] = int64(i) 2167 } 2168 } 2169 2170 batch.SetLength(coldata.BatchSize()) 2171 2172 for colIdx := 0; colIdx < nCols; colIdx++ { 2173 vec := batch.ColVec(colIdx) 2174 vec.Nulls().UnsetNulls() 2175 } 2176 return batch 2177 } 2178 2179 func newBatchOfRepeatedIntRows(nCols int, batch coldata.Batch, numRepeats int) coldata.Batch { 2180 for colIdx := 0; colIdx < nCols; colIdx++ { 2181 col := batch.ColVec(colIdx).Int64() 2182 for i := 0; i < coldata.BatchSize(); i++ { 2183 col[i] = int64((i + 1) / numRepeats) 2184 } 2185 } 2186 2187 batch.SetLength(coldata.BatchSize()) 2188 2189 for colIdx := 0; colIdx < nCols; colIdx++ { 2190 vec := batch.ColVec(colIdx) 2191 vec.Nulls().UnsetNulls() 2192 } 2193 return batch 2194 } 2195 2196 func BenchmarkMergeJoiner(b *testing.B) { 2197 ctx := context.Background() 2198 nCols := 4 2199 sourceTypes := make([]*types.T, nCols) 2200 2201 for colIdx := 0; colIdx < nCols; colIdx++ { 2202 sourceTypes[colIdx] = types.Int 2203 } 2204 2205 batch := testAllocator.NewMemBatch(sourceTypes) 2206 queueCfg, cleanup := colcontainerutils.NewTestingDiskQueueCfg(b, false /* inMem */) 2207 defer cleanup() 2208 benchMemAccount := testMemMonitor.MakeBoundAccount() 2209 defer benchMemAccount.Close(ctx) 2210 2211 // 1:1 join. 2212 for _, nBatches := range []int{1, 4, 16, 1024} { 2213 b.Run(fmt.Sprintf("rows=%d", nBatches*coldata.BatchSize()), func(b *testing.B) { 2214 // 8 (bytes / int64) * nBatches (number of batches) * col.BatchSize() (rows / 2215 // batch) * nCols (number of columns / row) * 2 (number of sources). 2216 b.SetBytes(int64(8 * nBatches * coldata.BatchSize() * nCols * 2)) 2217 b.ResetTimer() 2218 for i := 0; i < b.N; i++ { 2219 leftSource := newFiniteBatchSource(newBatchOfIntRows(nCols, batch), sourceTypes, nBatches) 2220 rightSource := newFiniteBatchSource(newBatchOfIntRows(nCols, batch), sourceTypes, nBatches) 2221 2222 benchMemAccount.Clear(ctx) 2223 base, err := newMergeJoinBase( 2224 colmem.NewAllocator(ctx, &benchMemAccount, testColumnFactory), defaultMemoryLimit, queueCfg, colexecbase.NewTestingSemaphore(mjFDLimit), 2225 sqlbase.InnerJoin, leftSource, rightSource, sourceTypes, sourceTypes, 2226 []execinfrapb.Ordering_Column{{ColIdx: 0, Direction: execinfrapb.Ordering_Column_ASC}}, 2227 []execinfrapb.Ordering_Column{{ColIdx: 0, Direction: execinfrapb.Ordering_Column_ASC}}, 2228 testDiskAcc, 2229 ) 2230 require.NoError(b, err) 2231 s := mergeJoinInnerOp{mergeJoinBase: base} 2232 s.Init() 2233 2234 b.StartTimer() 2235 for b := s.Next(ctx); b.Length() != 0; b = s.Next(ctx) { 2236 } 2237 b.StopTimer() 2238 } 2239 }) 2240 } 2241 2242 // Groups on left side. 2243 for _, nBatches := range []int{1, 4, 16, 1024} { 2244 b.Run(fmt.Sprintf("oneSideRepeat-rows=%d", nBatches*coldata.BatchSize()), func(b *testing.B) { 2245 // 8 (bytes / int64) * nBatches (number of batches) * col.BatchSize() (rows / 2246 // batch) * nCols (number of columns / row) * 2 (number of sources). 2247 b.SetBytes(int64(8 * nBatches * coldata.BatchSize() * nCols * 2)) 2248 b.ResetTimer() 2249 for i := 0; i < b.N; i++ { 2250 leftSource := newFiniteBatchSource(newBatchOfRepeatedIntRows(nCols, batch, nBatches), sourceTypes, nBatches) 2251 rightSource := newFiniteBatchSource(newBatchOfIntRows(nCols, batch), sourceTypes, nBatches) 2252 2253 benchMemAccount.Clear(ctx) 2254 base, err := newMergeJoinBase( 2255 colmem.NewAllocator(ctx, &benchMemAccount, testColumnFactory), defaultMemoryLimit, queueCfg, colexecbase.NewTestingSemaphore(mjFDLimit), 2256 sqlbase.InnerJoin, leftSource, rightSource, sourceTypes, sourceTypes, 2257 []execinfrapb.Ordering_Column{{ColIdx: 0, Direction: execinfrapb.Ordering_Column_ASC}}, 2258 []execinfrapb.Ordering_Column{{ColIdx: 0, Direction: execinfrapb.Ordering_Column_ASC}}, 2259 testDiskAcc, 2260 ) 2261 require.NoError(b, err) 2262 s := mergeJoinInnerOp{mergeJoinBase: base} 2263 s.Init() 2264 2265 b.StartTimer() 2266 for b := s.Next(ctx); b.Length() != 0; b = s.Next(ctx) { 2267 } 2268 b.StopTimer() 2269 } 2270 }) 2271 } 2272 2273 // Groups on both sides. 2274 for _, nBatches := range []int{1, 4, 16, 32} { 2275 numRepeats := nBatches 2276 b.Run(fmt.Sprintf("bothSidesRepeat-rows=%d", nBatches*coldata.BatchSize()), func(b *testing.B) { 2277 2278 // 8 (bytes / int64) * nBatches (number of batches) * col.BatchSize() (rows / 2279 // batch) * nCols (number of columns / row) * 2 (number of sources). 2280 b.SetBytes(int64(8 * nBatches * coldata.BatchSize() * nCols * 2)) 2281 b.ResetTimer() 2282 for i := 0; i < b.N; i++ { 2283 leftSource := newFiniteBatchSource(newBatchOfRepeatedIntRows(nCols, batch, numRepeats), sourceTypes, nBatches) 2284 rightSource := newFiniteBatchSource(newBatchOfRepeatedIntRows(nCols, batch, numRepeats), sourceTypes, nBatches) 2285 2286 benchMemAccount.Clear(ctx) 2287 base, err := newMergeJoinBase( 2288 colmem.NewAllocator(ctx, &benchMemAccount, testColumnFactory), defaultMemoryLimit, queueCfg, colexecbase.NewTestingSemaphore(mjFDLimit), 2289 sqlbase.InnerJoin, leftSource, rightSource, sourceTypes, sourceTypes, 2290 []execinfrapb.Ordering_Column{{ColIdx: 0, Direction: execinfrapb.Ordering_Column_ASC}}, 2291 []execinfrapb.Ordering_Column{{ColIdx: 0, Direction: execinfrapb.Ordering_Column_ASC}}, 2292 testDiskAcc, 2293 ) 2294 require.NoError(b, err) 2295 s := mergeJoinInnerOp{mergeJoinBase: base} 2296 s.Init() 2297 2298 b.StartTimer() 2299 for b := s.Next(ctx); b.Length() != 0; b = s.Next(ctx) { 2300 } 2301 b.StopTimer() 2302 } 2303 }) 2304 } 2305 2306 }