vitess.io/vitess@v0.16.2/go/vt/vtgate/engine/join_test.go (about) 1 /* 2 Copyright 2019 The Vitess Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package engine 18 19 import ( 20 "context" 21 "errors" 22 "testing" 23 24 "github.com/stretchr/testify/require" 25 26 "vitess.io/vitess/go/sqltypes" 27 28 querypb "vitess.io/vitess/go/vt/proto/query" 29 ) 30 31 func TestJoinExecute(t *testing.T) { 32 leftPrim := &fakePrimitive{ 33 results: []*sqltypes.Result{ 34 sqltypes.MakeTestResult( 35 sqltypes.MakeTestFields( 36 "col1|col2|col3", 37 "int64|varchar|varchar", 38 ), 39 "1|a|aa", 40 "2|b|bb", 41 "3|c|cc", 42 ), 43 }, 44 } 45 rightFields := sqltypes.MakeTestFields( 46 "col4|col5|col6", 47 "int64|varchar|varchar", 48 ) 49 rightPrim := &fakePrimitive{ 50 results: []*sqltypes.Result{ 51 sqltypes.MakeTestResult( 52 rightFields, 53 "4|d|dd", 54 ), 55 sqltypes.MakeTestResult( 56 rightFields, 57 ), 58 sqltypes.MakeTestResult( 59 rightFields, 60 "5|e|ee", 61 "6|f|ff", 62 "7|g|gg", 63 ), 64 }, 65 } 66 bv := map[string]*querypb.BindVariable{ 67 "a": sqltypes.Int64BindVariable(10), 68 } 69 70 // Normal join 71 jn := &Join{ 72 Opcode: InnerJoin, 73 Left: leftPrim, 74 Right: rightPrim, 75 Cols: []int{-1, -2, 1, 2}, 76 Vars: map[string]int{ 77 "bv": 1, 78 }, 79 } 80 r, err := jn.TryExecute(context.Background(), &noopVCursor{}, bv, true) 81 if err != nil { 82 t.Fatal(err) 83 } 84 leftPrim.ExpectLog(t, []string{ 85 `Execute a: type:INT64 value:"10" true`, 86 }) 87 rightPrim.ExpectLog(t, []string{ 88 `Execute a: type:INT64 value:"10" bv: type:VARCHAR value:"a" true`, 89 `Execute a: type:INT64 value:"10" bv: type:VARCHAR value:"b" false`, 90 `Execute a: type:INT64 value:"10" bv: type:VARCHAR value:"c" false`, 91 }) 92 expectResult(t, "jn.Execute", r, sqltypes.MakeTestResult( 93 sqltypes.MakeTestFields( 94 "col1|col2|col4|col5", 95 "int64|varchar|int64|varchar", 96 ), 97 "1|a|4|d", 98 "3|c|5|e", 99 "3|c|6|f", 100 "3|c|7|g", 101 )) 102 103 // Left Join 104 leftPrim.rewind() 105 rightPrim.rewind() 106 jn.Opcode = LeftJoin 107 r, err = jn.TryExecute(context.Background(), &noopVCursor{}, bv, true) 108 if err != nil { 109 t.Fatal(err) 110 } 111 leftPrim.ExpectLog(t, []string{ 112 `Execute a: type:INT64 value:"10" true`, 113 }) 114 rightPrim.ExpectLog(t, []string{ 115 `Execute a: type:INT64 value:"10" bv: type:VARCHAR value:"a" true`, 116 `Execute a: type:INT64 value:"10" bv: type:VARCHAR value:"b" false`, 117 `Execute a: type:INT64 value:"10" bv: type:VARCHAR value:"c" false`, 118 }) 119 expectResult(t, "jn.Execute", r, sqltypes.MakeTestResult( 120 sqltypes.MakeTestFields( 121 "col1|col2|col4|col5", 122 "int64|varchar|int64|varchar", 123 ), 124 "1|a|4|d", 125 "2|b|null|null", 126 "3|c|5|e", 127 "3|c|6|f", 128 "3|c|7|g", 129 )) 130 } 131 132 func TestJoinExecuteMaxMemoryRows(t *testing.T) { 133 saveMax := testMaxMemoryRows 134 saveIgnore := testIgnoreMaxMemoryRows 135 testMaxMemoryRows = 3 136 defer func() { 137 testMaxMemoryRows = saveMax 138 testIgnoreMaxMemoryRows = saveIgnore 139 }() 140 141 testCases := []struct { 142 ignoreMaxMemoryRows bool 143 err string 144 }{ 145 {true, ""}, 146 {false, "in-memory row count exceeded allowed limit of 3"}, 147 } 148 for _, test := range testCases { 149 leftPrim := &fakePrimitive{ 150 results: []*sqltypes.Result{ 151 sqltypes.MakeTestResult( 152 sqltypes.MakeTestFields( 153 "col1|col2|col3", 154 "int64|varchar|varchar", 155 ), 156 "1|a|aa", 157 "2|b|bb", 158 "3|c|cc", 159 ), 160 }, 161 } 162 rightFields := sqltypes.MakeTestFields( 163 "col4|col5|col6", 164 "int64|varchar|varchar", 165 ) 166 rightPrim := &fakePrimitive{ 167 results: []*sqltypes.Result{ 168 sqltypes.MakeTestResult( 169 rightFields, 170 "4|d|dd", 171 ), 172 sqltypes.MakeTestResult( 173 rightFields, 174 ), 175 sqltypes.MakeTestResult( 176 rightFields, 177 "5|e|ee", 178 "6|f|ff", 179 "7|g|gg", 180 ), 181 }, 182 } 183 bv := map[string]*querypb.BindVariable{ 184 "a": sqltypes.Int64BindVariable(10), 185 } 186 187 // Normal join 188 jn := &Join{ 189 Opcode: InnerJoin, 190 Left: leftPrim, 191 Right: rightPrim, 192 Cols: []int{-1, -2, 1, 2}, 193 Vars: map[string]int{ 194 "bv": 1, 195 }, 196 } 197 testIgnoreMaxMemoryRows = test.ignoreMaxMemoryRows 198 _, err := jn.TryExecute(context.Background(), &noopVCursor{}, bv, true) 199 if testIgnoreMaxMemoryRows { 200 require.NoError(t, err) 201 } else { 202 require.EqualError(t, err, test.err) 203 } 204 } 205 } 206 207 func TestJoinExecuteNoResult(t *testing.T) { 208 leftPrim := &fakePrimitive{ 209 results: []*sqltypes.Result{ 210 sqltypes.MakeTestResult( 211 sqltypes.MakeTestFields( 212 "col1|col2|col3", 213 "int64|varchar|varchar", 214 ), 215 ), 216 }, 217 } 218 rightFields := sqltypes.MakeTestFields( 219 "col4|col5|col6", 220 "int64|varchar|varchar", 221 ) 222 rightPrim := &fakePrimitive{ 223 results: []*sqltypes.Result{ 224 sqltypes.MakeTestResult( 225 rightFields, 226 ), 227 }, 228 } 229 230 jn := &Join{ 231 Opcode: InnerJoin, 232 Left: leftPrim, 233 Right: rightPrim, 234 Cols: []int{-1, -2, 1, 2}, 235 Vars: map[string]int{ 236 "bv": 1, 237 }, 238 } 239 r, err := jn.TryExecute(context.Background(), &noopVCursor{}, map[string]*querypb.BindVariable{}, true) 240 if err != nil { 241 t.Fatal(err) 242 } 243 leftPrim.ExpectLog(t, []string{ 244 `Execute true`, 245 }) 246 rightPrim.ExpectLog(t, []string{ 247 `GetFields bv: `, 248 `Execute bv: true`, 249 }) 250 wantResult := sqltypes.MakeTestResult( 251 sqltypes.MakeTestFields( 252 "col1|col2|col4|col5", 253 "int64|varchar|int64|varchar", 254 ), 255 ) 256 expectResult(t, "jn.Execute", r, wantResult) 257 } 258 259 func TestJoinExecuteErrors(t *testing.T) { 260 // Error on left query 261 leftPrim := &fakePrimitive{ 262 sendErr: errors.New("left err"), 263 } 264 265 jn := &Join{ 266 Opcode: InnerJoin, 267 Left: leftPrim, 268 } 269 _, err := jn.TryExecute(context.Background(), &noopVCursor{}, map[string]*querypb.BindVariable{}, true) 270 require.EqualError(t, err, "left err") 271 272 // Error on right query 273 leftPrim = &fakePrimitive{ 274 results: []*sqltypes.Result{ 275 sqltypes.MakeTestResult( 276 sqltypes.MakeTestFields( 277 "col1|col2|col3", 278 "int64|varchar|varchar", 279 ), 280 "1|a|aa", 281 "2|b|bb", 282 "3|c|cc", 283 ), 284 }, 285 } 286 rightPrim := &fakePrimitive{ 287 sendErr: errors.New("right err"), 288 } 289 290 jn = &Join{ 291 Opcode: InnerJoin, 292 Left: leftPrim, 293 Right: rightPrim, 294 Cols: []int{-1, -2, 1, 2}, 295 Vars: map[string]int{ 296 "bv": 1, 297 }, 298 } 299 _, err = jn.TryExecute(context.Background(), &noopVCursor{}, map[string]*querypb.BindVariable{}, true) 300 require.EqualError(t, err, "right err") 301 302 // Error on right getfields 303 leftPrim = &fakePrimitive{ 304 results: []*sqltypes.Result{ 305 sqltypes.MakeTestResult( 306 sqltypes.MakeTestFields( 307 "col1|col2|col3", 308 "int64|varchar|varchar", 309 ), 310 ), 311 }, 312 } 313 rightPrim = &fakePrimitive{ 314 sendErr: errors.New("right err"), 315 } 316 317 jn = &Join{ 318 Opcode: InnerJoin, 319 Left: leftPrim, 320 Right: rightPrim, 321 Cols: []int{-1, -2, 1, 2}, 322 Vars: map[string]int{ 323 "bv": 1, 324 }, 325 } 326 _, err = jn.TryExecute(context.Background(), &noopVCursor{}, map[string]*querypb.BindVariable{}, true) 327 require.EqualError(t, err, "right err") 328 } 329 330 func TestJoinStreamExecute(t *testing.T) { 331 leftPrim := &fakePrimitive{ 332 results: []*sqltypes.Result{ 333 sqltypes.MakeTestResult( 334 sqltypes.MakeTestFields( 335 "col1|col2|col3", 336 "int64|varchar|varchar", 337 ), 338 "1|a|aa", 339 "2|b|bb", 340 "3|c|cc", 341 ), 342 }, 343 } 344 rightFields := sqltypes.MakeTestFields( 345 "col4|col5|col6", 346 "int64|varchar|varchar", 347 ) 348 rightPrim := &fakePrimitive{ 349 results: []*sqltypes.Result{ 350 // First right query will always be a GetFields. 351 sqltypes.MakeTestResult( 352 rightFields, 353 ), 354 sqltypes.MakeTestResult( 355 rightFields, 356 "4|d|dd", 357 ), 358 sqltypes.MakeTestResult( 359 rightFields, 360 ), 361 sqltypes.MakeTestResult( 362 rightFields, 363 "5|e|ee", 364 "6|f|ff", 365 "7|g|gg", 366 ), 367 }, 368 } 369 370 // Normal join 371 jn := &Join{ 372 Opcode: InnerJoin, 373 Left: leftPrim, 374 Right: rightPrim, 375 Cols: []int{-1, -2, 1, 2}, 376 Vars: map[string]int{ 377 "bv": 1, 378 }, 379 } 380 r, err := wrapStreamExecute(jn, &noopVCursor{}, map[string]*querypb.BindVariable{}, true) 381 if err != nil { 382 t.Fatal(err) 383 } 384 leftPrim.ExpectLog(t, []string{ 385 `StreamExecute true`, 386 }) 387 rightPrim.ExpectLog(t, []string{ 388 `GetFields bv: `, 389 `Execute bv: true`, 390 `StreamExecute bv: type:VARCHAR value:"a" false`, 391 `StreamExecute bv: type:VARCHAR value:"b" false`, 392 `StreamExecute bv: type:VARCHAR value:"c" false`, 393 }) 394 expectResult(t, "jn.Execute", r, sqltypes.MakeTestResult( 395 sqltypes.MakeTestFields( 396 "col1|col2|col4|col5", 397 "int64|varchar|int64|varchar", 398 ), 399 "1|a|4|d", 400 "3|c|5|e", 401 "3|c|6|f", 402 "3|c|7|g", 403 )) 404 405 // Left Join 406 leftPrim.rewind() 407 rightPrim.rewind() 408 jn.Opcode = LeftJoin 409 r, err = wrapStreamExecute(jn, &noopVCursor{}, map[string]*querypb.BindVariable{}, true) 410 if err != nil { 411 t.Fatal(err) 412 } 413 leftPrim.ExpectLog(t, []string{ 414 `StreamExecute true`, 415 }) 416 rightPrim.ExpectLog(t, []string{ 417 `GetFields bv: `, 418 `Execute bv: true`, 419 `StreamExecute bv: type:VARCHAR value:"a" false`, 420 `StreamExecute bv: type:VARCHAR value:"b" false`, 421 `StreamExecute bv: type:VARCHAR value:"c" false`, 422 }) 423 expectResult(t, "jn.Execute", r, sqltypes.MakeTestResult( 424 sqltypes.MakeTestFields( 425 "col1|col2|col4|col5", 426 "int64|varchar|int64|varchar", 427 ), 428 "1|a|4|d", 429 "2|b|null|null", 430 "3|c|5|e", 431 "3|c|6|f", 432 "3|c|7|g", 433 )) 434 } 435 436 func TestGetFields(t *testing.T) { 437 leftPrim := &fakePrimitive{ 438 results: []*sqltypes.Result{ 439 sqltypes.MakeTestResult( 440 sqltypes.MakeTestFields( 441 "col1|col2|col3", 442 "int64|varchar|varchar", 443 ), 444 ), 445 }, 446 } 447 rightFields := sqltypes.MakeTestFields( 448 "col4|col5|col6", 449 "int64|varchar|varchar", 450 ) 451 rightPrim := &fakePrimitive{ 452 results: []*sqltypes.Result{ 453 sqltypes.MakeTestResult( 454 rightFields, 455 ), 456 }, 457 } 458 459 jn := &Join{ 460 Opcode: InnerJoin, 461 Left: leftPrim, 462 Right: rightPrim, 463 Cols: []int{-1, -2, 1, 2}, 464 Vars: map[string]int{ 465 "bv": 1, 466 }, 467 } 468 r, err := jn.GetFields(context.Background(), nil, map[string]*querypb.BindVariable{}) 469 if err != nil { 470 t.Fatal(err) 471 } 472 leftPrim.ExpectLog(t, []string{ 473 `GetFields `, 474 `Execute true`, 475 }) 476 rightPrim.ExpectLog(t, []string{ 477 `GetFields bv: `, 478 `Execute bv: true`, 479 }) 480 expectResult(t, "jn.Execute", r, sqltypes.MakeTestResult( 481 sqltypes.MakeTestFields( 482 "col1|col2|col4|col5", 483 "int64|varchar|int64|varchar", 484 ), 485 )) 486 } 487 488 func TestGetFieldsErrors(t *testing.T) { 489 leftPrim := &fakePrimitive{ 490 sendErr: errors.New("left err"), 491 } 492 rightPrim := &fakePrimitive{ 493 sendErr: errors.New("right err"), 494 } 495 496 jn := &Join{ 497 Opcode: InnerJoin, 498 Left: leftPrim, 499 Right: rightPrim, 500 Cols: []int{-1, -2, 1, 2}, 501 Vars: map[string]int{ 502 "bv": 1, 503 }, 504 } 505 _, err := jn.GetFields(context.Background(), nil, map[string]*querypb.BindVariable{}) 506 require.EqualError(t, err, "left err") 507 508 jn.Left = &fakePrimitive{ 509 results: []*sqltypes.Result{ 510 sqltypes.MakeTestResult( 511 sqltypes.MakeTestFields( 512 "col1|col2|col3", 513 "int64|varchar|varchar", 514 ), 515 ), 516 }, 517 } 518 _, err = jn.GetFields(context.Background(), nil, map[string]*querypb.BindVariable{}) 519 require.EqualError(t, err, "right err") 520 }