vitess.io/vitess@v0.16.2/go/vt/vtgate/engine/delete_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 "vitess.io/vitess/go/mysql/collations" 25 "vitess.io/vitess/go/vt/vtgate/evalengine" 26 27 "github.com/stretchr/testify/require" 28 29 "vitess.io/vitess/go/sqltypes" 30 "vitess.io/vitess/go/vt/vtgate/vindexes" 31 32 querypb "vitess.io/vitess/go/vt/proto/query" 33 ) 34 35 func TestDeleteUnsharded(t *testing.T) { 36 del := &Delete{ 37 DML: &DML{ 38 RoutingParameters: &RoutingParameters{ 39 Opcode: Unsharded, 40 Keyspace: &vindexes.Keyspace{ 41 Name: "ks", 42 Sharded: false, 43 }, 44 }, 45 Query: "dummy_delete", 46 }, 47 } 48 49 vc := newDMLTestVCursor("0") 50 _, err := del.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false) 51 require.NoError(t, err) 52 vc.ExpectLog(t, []string{ 53 `ResolveDestinations ks [] Destinations:DestinationAllShards()`, 54 `ExecuteMultiShard ks.0: dummy_delete {} true true`, 55 }) 56 57 // Failure cases 58 vc = &loggingVCursor{shardErr: errors.New("shard_error")} 59 _, err = del.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false) 60 require.EqualError(t, err, "shard_error") 61 62 vc = &loggingVCursor{} 63 _, err = del.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false) 64 require.EqualError(t, err, "Keyspace 'ks' does not have exactly one shard: []") 65 } 66 67 func TestDeleteEqual(t *testing.T) { 68 vindex, _ := vindexes.NewHash("", nil) 69 del := &Delete{ 70 DML: &DML{ 71 RoutingParameters: &RoutingParameters{ 72 Opcode: Equal, 73 Keyspace: &vindexes.Keyspace{ 74 Name: "ks", 75 Sharded: true, 76 }, 77 Vindex: vindex, 78 Values: []evalengine.Expr{evalengine.NewLiteralInt(1)}, 79 }, 80 Query: "dummy_delete", 81 }, 82 } 83 84 vc := newDMLTestVCursor("-20", "20-") 85 _, err := del.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false) 86 require.NoError(t, err) 87 vc.ExpectLog(t, []string{ 88 `ResolveDestinations ks [type:INT64 value:"1"] Destinations:DestinationKeyspaceID(166b40b44aba4bd6)`, 89 `ExecuteMultiShard ks.-20: dummy_delete {} true true`, 90 }) 91 92 // Failure case 93 expr := evalengine.NewBindVar("aa", collations.TypedCollation{}) 94 del.Values = []evalengine.Expr{expr} 95 _, err = del.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false) 96 require.EqualError(t, err, "query arguments missing for aa") 97 } 98 99 func TestDeleteEqualMultiCol(t *testing.T) { 100 vindex, _ := vindexes.NewRegionExperimental("", map[string]string{"region_bytes": "1"}) 101 del := &Delete{ 102 DML: &DML{ 103 RoutingParameters: &RoutingParameters{ 104 Opcode: Equal, 105 Keyspace: &vindexes.Keyspace{ 106 Name: "ks", 107 Sharded: true, 108 }, 109 Vindex: vindex, 110 Values: []evalengine.Expr{evalengine.NewLiteralInt(1), evalengine.NewLiteralInt(2)}, 111 }, 112 Query: "dummy_delete", 113 }, 114 } 115 116 vc := newDMLTestVCursor("-20", "20-") 117 _, err := del.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false) 118 require.NoError(t, err) 119 vc.ExpectLog(t, []string{ 120 `ResolveDestinationsMultiCol ks [[INT64(1) INT64(2)]] Destinations:DestinationKeyspaceID(0106e7ea22ce92708f)`, 121 `ExecuteMultiShard ks.-20: dummy_delete {} true true`, 122 }) 123 124 // Failure case 125 expr := evalengine.NewBindVar("aa", collations.TypedCollation{}) 126 del.Values = []evalengine.Expr{expr} 127 _, err = del.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false) 128 require.EqualError(t, err, "query arguments missing for aa") 129 } 130 131 func TestDeleteEqualNoRoute(t *testing.T) { 132 vindex, _ := vindexes.NewLookupUnique("", map[string]string{ 133 "table": "lkp", 134 "from": "from", 135 "to": "toc", 136 }) 137 del := &Delete{ 138 DML: &DML{ 139 RoutingParameters: &RoutingParameters{ 140 Opcode: Equal, 141 Keyspace: &vindexes.Keyspace{ 142 Name: "ks", 143 Sharded: true, 144 }, 145 Vindex: vindex, 146 Values: []evalengine.Expr{evalengine.NewLiteralInt(1)}, 147 }, 148 Query: "dummy_delete", 149 }, 150 } 151 152 vc := newDMLTestVCursor("0") 153 _, err := del.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false) 154 require.NoError(t, err) 155 vc.ExpectLog(t, []string{ 156 // This lookup query will return no rows. So, the DML will not be sent anywhere. 157 `Execute select from, toc from lkp where from in ::from from: type:TUPLE values:{type:INT64 value:"1"} false`, 158 `ResolveDestinations ks [type:INT64 value:"1"] Destinations:DestinationNone()`, 159 }) 160 } 161 162 func TestDeleteEqualNoScatter(t *testing.T) { 163 t.Skip("planner does not produces this plan anymore") 164 vindex, _ := vindexes.NewLookupUnique("", map[string]string{ 165 "table": "lkp", 166 "from": "from", 167 "to": "toc", 168 "write_only": "true", 169 }) 170 del := &Delete{ 171 DML: &DML{ 172 RoutingParameters: &RoutingParameters{ 173 Opcode: Equal, 174 Keyspace: &vindexes.Keyspace{ 175 Name: "ks", 176 Sharded: true, 177 }, 178 Vindex: vindex, 179 Values: []evalengine.Expr{evalengine.NewLiteralInt(1)}, 180 }, 181 Query: "dummy_delete", 182 }, 183 } 184 185 vc := newDMLTestVCursor("0") 186 _, err := del.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false) 187 require.EqualError(t, err, "cannot map vindex to unique keyspace id: DestinationKeyRange(-)") 188 } 189 190 func TestDeleteOwnedVindex(t *testing.T) { 191 ks := buildTestVSchema().Keyspaces["sharded"] 192 del := &Delete{ 193 DML: &DML{ 194 RoutingParameters: &RoutingParameters{ 195 Opcode: Equal, 196 Keyspace: ks.Keyspace, 197 Vindex: ks.Vindexes["hash"], 198 Values: []evalengine.Expr{evalengine.NewLiteralInt(1)}, 199 }, 200 Query: "dummy_delete", 201 Table: []*vindexes.Table{ 202 ks.Tables["t1"], 203 }, 204 OwnedVindexQuery: "dummy_subquery", 205 KsidVindex: ks.Vindexes["hash"], 206 KsidLength: 1, 207 }, 208 } 209 210 results := []*sqltypes.Result{sqltypes.MakeTestResult( 211 sqltypes.MakeTestFields( 212 "id|c1|c2|c3", 213 "int64|int64|int64|int64", 214 ), 215 "1|4|5|6", 216 )} 217 218 vc := newDMLTestVCursor("-20", "20-") 219 vc.results = results 220 221 _, err := del.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false) 222 require.NoError(t, err) 223 vc.ExpectLog(t, []string{ 224 `ResolveDestinations sharded [type:INT64 value:"1"] Destinations:DestinationKeyspaceID(166b40b44aba4bd6)`, 225 // ResolveDestinations is hard-coded to return -20. 226 // It gets used to perform the subquery to fetch the changing column values. 227 `ExecuteMultiShard sharded.-20: dummy_subquery {} false false`, 228 // Those values are returned as 4,5 for twocol and 6 for onecol. 229 `Execute delete from lkp2 where from1 = :from1 and from2 = :from2 and toc = :toc from1: type:INT64 value:"4" from2: type:INT64 value:"5" toc: type:VARBINARY value:"\x16k@\xb4J\xbaK\xd6" true`, 230 `Execute delete from lkp1 where from = :from and toc = :toc from: type:INT64 value:"6" toc: type:VARBINARY value:"\x16k@\xb4J\xbaK\xd6" true`, 231 // Finally, the actual delete, which is also sent to -20, same route as the subquery. 232 `ExecuteMultiShard sharded.-20: dummy_delete {} true true`, 233 }) 234 235 // No rows changing 236 vc = newDMLTestVCursor("-20", "20-") 237 _, err = del.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false) 238 require.NoError(t, err) 239 vc.ExpectLog(t, []string{ 240 `ResolveDestinations sharded [type:INT64 value:"1"] Destinations:DestinationKeyspaceID(166b40b44aba4bd6)`, 241 // ResolveDestinations is hard-coded to return -20. 242 // It gets used to perform the subquery to fetch the changing column values. 243 `ExecuteMultiShard sharded.-20: dummy_subquery {} false false`, 244 // Subquery returns no rows. So, no vindexes are deleted. We still pass-through the original delete. 245 `ExecuteMultiShard sharded.-20: dummy_delete {} true true`, 246 }) 247 248 // Delete can affect multiple rows 249 results = []*sqltypes.Result{sqltypes.MakeTestResult( 250 sqltypes.MakeTestFields( 251 "id|c1|c2|c3", 252 "int64|int64|int64|int64", 253 ), 254 "1|4|5|6", 255 "1|7|8|9", 256 )} 257 vc = newDMLTestVCursor("-20", "20-") 258 vc.results = results 259 260 _, err = del.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false) 261 require.NoError(t, err) 262 vc.ExpectLog(t, []string{ 263 `ResolveDestinations sharded [type:INT64 value:"1"] Destinations:DestinationKeyspaceID(166b40b44aba4bd6)`, 264 // ResolveDestinations is hard-coded to return -20. 265 // It gets used to perform the subquery to fetch the changing column values. 266 `ExecuteMultiShard sharded.-20: dummy_subquery {} false false`, 267 // Delete 4,5 and 7,8 from lkp2. 268 // Delete 6 and 8 from lkp1. 269 `Execute delete from lkp2 where from1 = :from1 and from2 = :from2 and toc = :toc from1: type:INT64 value:"4" from2: type:INT64 value:"5" toc: type:VARBINARY value:"\x16k@\xb4J\xbaK\xd6" true`, 270 `Execute delete from lkp1 where from = :from and toc = :toc from: type:INT64 value:"6" toc: type:VARBINARY value:"\x16k@\xb4J\xbaK\xd6" true`, 271 `Execute delete from lkp2 where from1 = :from1 and from2 = :from2 and toc = :toc from1: type:INT64 value:"7" from2: type:INT64 value:"8" toc: type:VARBINARY value:"\x16k@\xb4J\xbaK\xd6" true`, 272 `Execute delete from lkp1 where from = :from and toc = :toc from: type:INT64 value:"9" toc: type:VARBINARY value:"\x16k@\xb4J\xbaK\xd6" true`, 273 // Send the DML. 274 `ExecuteMultiShard sharded.-20: dummy_delete {} true true`, 275 }) 276 } 277 278 func TestDeleteOwnedVindexMultiCol(t *testing.T) { 279 ks := buildTestVSchema().Keyspaces["sharded"] 280 del := &Delete{ 281 DML: &DML{ 282 RoutingParameters: &RoutingParameters{ 283 Opcode: Equal, 284 Keyspace: ks.Keyspace, 285 Vindex: ks.Vindexes["rg_vdx"], 286 Values: []evalengine.Expr{evalengine.NewLiteralInt(1), evalengine.NewLiteralInt(2)}, 287 }, 288 Query: "dummy_delete", 289 Table: []*vindexes.Table{ 290 ks.Tables["rg_tbl"], 291 }, 292 OwnedVindexQuery: "dummy_subquery", 293 KsidVindex: ks.Vindexes["rg_vdx"], 294 KsidLength: 2, 295 }, 296 } 297 298 results := []*sqltypes.Result{sqltypes.MakeTestResult( 299 sqltypes.MakeTestFields( 300 "cola|colb|colc", 301 "int64|int64|int64", 302 ), 303 "1|2|4", 304 )} 305 306 vc := newDMLTestVCursor("-20", "20-") 307 vc.results = results 308 309 _, err := del.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false) 310 require.NoError(t, err) 311 vc.ExpectLog(t, []string{ 312 `ResolveDestinationsMultiCol sharded [[INT64(1) INT64(2)]] Destinations:DestinationKeyspaceID(0106e7ea22ce92708f)`, 313 // ResolveDestinations is hard-coded to return -20. 314 // It gets used to perform the subquery to fetch the changing column values. 315 `ExecuteMultiShard sharded.-20: dummy_subquery {} false false`, 316 // 4 returned for lkp_rg. 317 `Execute delete from lkp_rg_tbl where from = :from and toc = :toc from: type:INT64 value:"4" toc: type:VARBINARY value:"\x01\x06\xe7\xea\"Βp\x8f" true`, 318 // Finally, the actual delete, which is also sent to -20, same route as the subquery. 319 `ExecuteMultiShard sharded.-20: dummy_delete {} true true`, 320 }) 321 322 // No rows changing 323 vc.Rewind() 324 vc.results = nil 325 _, err = del.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false) 326 require.NoError(t, err) 327 vc.ExpectLog(t, []string{ 328 `ResolveDestinationsMultiCol sharded [[INT64(1) INT64(2)]] Destinations:DestinationKeyspaceID(0106e7ea22ce92708f)`, 329 // ResolveDestinations is hard-coded to return -20. 330 // It gets used to perform the subquery to fetch the changing column values. 331 `ExecuteMultiShard sharded.-20: dummy_subquery {} false false`, 332 // Subquery returns no rows. So, no vindexes are deleted. We still pass-through the original delete. 333 `ExecuteMultiShard sharded.-20: dummy_delete {} true true`, 334 }) 335 336 // Delete can affect multiple rows 337 results = []*sqltypes.Result{sqltypes.MakeTestResult( 338 sqltypes.MakeTestFields( 339 "cola|colb|colc", 340 "int64|int64|int64", 341 ), 342 "1|2|4", 343 "1|2|6", 344 )} 345 vc.Rewind() 346 vc.results = results 347 348 _, err = del.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false) 349 require.NoError(t, err) 350 vc.ExpectLog(t, []string{ 351 `ResolveDestinationsMultiCol sharded [[INT64(1) INT64(2)]] Destinations:DestinationKeyspaceID(0106e7ea22ce92708f)`, 352 // ResolveDestinations is hard-coded to return -20. 353 // It gets used to perform the subquery to fetch the changing column values. 354 `ExecuteMultiShard sharded.-20: dummy_subquery {} false false`, 355 // Delete 4 and 6 from lkp_rg. 356 `Execute delete from lkp_rg_tbl where from = :from and toc = :toc from: type:INT64 value:"4" toc: type:VARBINARY value:"\x01\x06\xe7\xea\"Βp\x8f" true`, 357 `Execute delete from lkp_rg_tbl where from = :from and toc = :toc from: type:INT64 value:"6" toc: type:VARBINARY value:"\x01\x06\xe7\xea\"Βp\x8f" true`, 358 // Send the DML. 359 `ExecuteMultiShard sharded.-20: dummy_delete {} true true`, 360 }) 361 } 362 363 func TestDeleteSharded(t *testing.T) { 364 ks := buildTestVSchema().Keyspaces["sharded"] 365 del := &Delete{ 366 DML: &DML{ 367 RoutingParameters: &RoutingParameters{ 368 Opcode: Scatter, 369 Keyspace: ks.Keyspace, 370 }, 371 Query: "dummy_delete", 372 Table: []*vindexes.Table{ 373 ks.Tables["t2"], 374 }, 375 }, 376 } 377 378 vc := newDMLTestVCursor("-20", "20-") 379 _, err := del.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false) 380 require.NoError(t, err) 381 vc.ExpectLog(t, []string{ 382 `ResolveDestinations sharded [] Destinations:DestinationAllShards()`, 383 `ExecuteMultiShard sharded.-20: dummy_delete {} sharded.20-: dummy_delete {} true false`, 384 }) 385 386 // Failure case 387 vc = &loggingVCursor{shardErr: errors.New("shard_error")} 388 _, err = del.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false) 389 require.EqualError(t, err, "shard_error") 390 } 391 392 func TestDeleteShardedStreaming(t *testing.T) { 393 ks := buildTestVSchema().Keyspaces["sharded"] 394 del := &Delete{ 395 DML: &DML{ 396 RoutingParameters: &RoutingParameters{ 397 Opcode: Scatter, 398 Keyspace: ks.Keyspace, 399 }, 400 Query: "dummy_delete", 401 Table: []*vindexes.Table{ 402 ks.Tables["t2"], 403 }, 404 }, 405 } 406 407 vc := newDMLTestVCursor("-20", "20-") 408 err := del.TryStreamExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false, func(result *sqltypes.Result) error { 409 return nil 410 }) 411 require.NoError(t, err) 412 vc.ExpectLog(t, []string{ 413 `ResolveDestinations sharded [] Destinations:DestinationAllShards()`, 414 `ExecuteMultiShard sharded.-20: dummy_delete {} sharded.20-: dummy_delete {} true false`, 415 }) 416 } 417 418 func TestDeleteScatterOwnedVindex(t *testing.T) { 419 ks := buildTestVSchema().Keyspaces["sharded"] 420 del := &Delete{ 421 DML: &DML{ 422 RoutingParameters: &RoutingParameters{ 423 Opcode: Scatter, 424 Keyspace: ks.Keyspace, 425 }, 426 Query: "dummy_delete", 427 Table: []*vindexes.Table{ 428 ks.Tables["t1"], 429 }, 430 OwnedVindexQuery: "dummy_subquery", 431 KsidVindex: ks.Vindexes["hash"], 432 KsidLength: 1, 433 }, 434 } 435 436 results := []*sqltypes.Result{sqltypes.MakeTestResult( 437 sqltypes.MakeTestFields( 438 "id|c1|c2|c3", 439 "int64|int64|int64|int64", 440 ), 441 "1|4|5|6", 442 )} 443 444 vc := newDMLTestVCursor("-20", "20-") 445 vc.results = results 446 447 _, err := del.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false) 448 require.NoError(t, err) 449 vc.ExpectLog(t, []string{ 450 `ResolveDestinations sharded [] Destinations:DestinationAllShards()`, 451 // ResolveDestinations is hard-coded to return -20. 452 // It gets used to perform the subquery to fetch the changing column values. 453 `ExecuteMultiShard sharded.-20: dummy_subquery {} sharded.20-: dummy_subquery {} false false`, 454 // Those values are returned as 4,5 for twocol and 6 for onecol. 455 `Execute delete from lkp2 where from1 = :from1 and from2 = :from2 and toc = :toc from1: type:INT64 value:"4" from2: type:INT64 value:"5" toc: type:VARBINARY value:"\x16k@\xb4J\xbaK\xd6" true`, 456 `Execute delete from lkp1 where from = :from and toc = :toc from: type:INT64 value:"6" toc: type:VARBINARY value:"\x16k@\xb4J\xbaK\xd6" true`, 457 // Finally, the actual delete, which is also sent to -20, same route as the subquery. 458 `ExecuteMultiShard sharded.-20: dummy_delete {} sharded.20-: dummy_delete {} true false`, 459 }) 460 461 // No rows changing 462 vc = newDMLTestVCursor("-20", "20-") 463 464 _, err = del.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false) 465 require.NoError(t, err) 466 vc.ExpectLog(t, []string{ 467 `ResolveDestinations sharded [] Destinations:DestinationAllShards()`, 468 // ResolveDestinations is hard-coded to return -20. 469 // It gets used to perform the subquery to fetch the changing column values. 470 `ExecuteMultiShard sharded.-20: dummy_subquery {} sharded.20-: dummy_subquery {} false false`, 471 // Subquery returns no rows. So, no vindexes are deleted. We still pass-through the original delete. 472 `ExecuteMultiShard sharded.-20: dummy_delete {} sharded.20-: dummy_delete {} true false`, 473 }) 474 475 // Delete can affect multiple rows 476 results = []*sqltypes.Result{sqltypes.MakeTestResult( 477 sqltypes.MakeTestFields( 478 "id|c1|c2|c3", 479 "int64|int64|int64|int64", 480 ), 481 "1|4|5|6", 482 "1|7|8|9", 483 )} 484 vc = newDMLTestVCursor("-20", "20-") 485 vc.results = results 486 487 _, err = del.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false) 488 require.NoError(t, err) 489 vc.ExpectLog(t, []string{ 490 `ResolveDestinations sharded [] Destinations:DestinationAllShards()`, 491 // ResolveDestinations is hard-coded to return -20. 492 // It gets used to perform the subquery to fetch the changing column values. 493 `ExecuteMultiShard sharded.-20: dummy_subquery {} sharded.20-: dummy_subquery {} false false`, 494 // Delete 4,5 and 7,8 from lkp2. 495 // Delete 6 and 8 from lkp1. 496 `Execute delete from lkp2 where from1 = :from1 and from2 = :from2 and toc = :toc from1: type:INT64 value:"4" from2: type:INT64 value:"5" toc: type:VARBINARY value:"\x16k@\xb4J\xbaK\xd6" true`, 497 `Execute delete from lkp1 where from = :from and toc = :toc from: type:INT64 value:"6" toc: type:VARBINARY value:"\x16k@\xb4J\xbaK\xd6" true`, 498 `Execute delete from lkp2 where from1 = :from1 and from2 = :from2 and toc = :toc from1: type:INT64 value:"7" from2: type:INT64 value:"8" toc: type:VARBINARY value:"\x16k@\xb4J\xbaK\xd6" true`, 499 `Execute delete from lkp1 where from = :from and toc = :toc from: type:INT64 value:"9" toc: type:VARBINARY value:"\x16k@\xb4J\xbaK\xd6" true`, 500 // Send the DML. 501 `ExecuteMultiShard sharded.-20: dummy_delete {} sharded.20-: dummy_delete {} true false`, 502 }) 503 } 504 505 func TestDeleteInChangedVindexMultiCol(t *testing.T) { 506 ks := buildTestVSchema().Keyspaces["sharded"] 507 del := &Delete{ 508 DML: &DML{ 509 RoutingParameters: &RoutingParameters{ 510 Opcode: IN, 511 Keyspace: ks.Keyspace, 512 Vindex: ks.Vindexes["rg_vdx"], 513 Values: []evalengine.Expr{ 514 evalengine.TupleExpr{evalengine.NewLiteralInt(1), evalengine.NewLiteralInt(2)}, 515 evalengine.NewLiteralInt(3), 516 }, 517 }, 518 Query: "dummy_update", 519 Table: []*vindexes.Table{ 520 ks.Tables["rg_tbl"], 521 }, 522 OwnedVindexQuery: "dummy_subquery", 523 KsidVindex: ks.Vindexes["rg_vdx"], 524 KsidLength: 2, 525 }, 526 } 527 528 results := []*sqltypes.Result{sqltypes.MakeTestResult( 529 sqltypes.MakeTestFields( 530 "cola|colb|colc", 531 "int64|int64|int64", 532 ), 533 "1|3|4", 534 "2|3|5", 535 "1|3|6", 536 "2|3|7", 537 )} 538 vc := newDMLTestVCursor("-20", "20-") 539 vc.results = results 540 541 _, err := del.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false) 542 require.NoError(t, err) 543 vc.ExpectLog(t, []string{ 544 `ResolveDestinationsMultiCol sharded [[INT64(1) INT64(3)] [INT64(2) INT64(3)]] Destinations:DestinationKeyspaceID(014eb190c9a2fa169c),DestinationKeyspaceID(024eb190c9a2fa169c)`, 545 // ResolveDestinations is hard-coded to return -20. 546 // It gets used to perform the subquery to fetch the changing column values. 547 `ExecuteMultiShard sharded.-20: dummy_subquery {} false false`, 548 // Those values are returned as 4,5,6 and 7 for colc 549 `Execute delete from lkp_rg_tbl where from = :from and toc = :toc from: type:INT64 value:"4" toc: type:VARBINARY value:"\x01N\xb1\x90ɢ\xfa\x16\x9c" true`, 550 `Execute delete from lkp_rg_tbl where from = :from and toc = :toc from: type:INT64 value:"5" toc: type:VARBINARY value:"\x02N\xb1\x90ɢ\xfa\x16\x9c" true`, 551 `Execute delete from lkp_rg_tbl where from = :from and toc = :toc from: type:INT64 value:"6" toc: type:VARBINARY value:"\x01N\xb1\x90ɢ\xfa\x16\x9c" true`, 552 `Execute delete from lkp_rg_tbl where from = :from and toc = :toc from: type:INT64 value:"7" toc: type:VARBINARY value:"\x02N\xb1\x90ɢ\xfa\x16\x9c" true`, 553 // Finally, the actual delete, which is also sent to -20, same route as the subquery. 554 `ExecuteMultiShard sharded.-20: dummy_update {} true true`, 555 }) 556 } 557 558 func TestDeleteEqualSubshard(t *testing.T) { 559 vindex, _ := vindexes.NewRegionExperimental("", map[string]string{"region_bytes": "1"}) 560 del := &Delete{ 561 DML: &DML{ 562 RoutingParameters: &RoutingParameters{ 563 Opcode: SubShard, 564 Keyspace: &vindexes.Keyspace{ 565 Name: "ks", 566 Sharded: true, 567 }, 568 Vindex: vindex, 569 Values: []evalengine.Expr{evalengine.NewLiteralInt(1)}, 570 }, 571 Query: "dummy_delete", 572 }, 573 } 574 575 vc := newDMLTestVCursor("-20", "20-") 576 vc.shardForKsid = []string{"-20", "20-"} 577 _, err := del.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false) 578 require.NoError(t, err) 579 vc.ExpectLog(t, []string{ 580 `ResolveDestinationsMultiCol ks [[INT64(1)]] Destinations:DestinationKeyRange(01-02)`, 581 `ExecuteMultiShard ks.-20: dummy_delete {} ks.20-: dummy_delete {} true false`, 582 }) 583 584 vc.Rewind() 585 // as it is single shard so autocommit should be allowed. 586 vc.shardForKsid = []string{"-20"} 587 _, err = del.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false) 588 require.NoError(t, err) 589 vc.ExpectLog(t, []string{ 590 `ResolveDestinationsMultiCol ks [[INT64(1)]] Destinations:DestinationKeyRange(01-02)`, 591 `ExecuteMultiShard ks.-20: dummy_delete {} true true`, 592 }) 593 } 594 595 func TestDeleteMultiEqual(t *testing.T) { 596 ks := buildTestVSchema().Keyspaces["sharded"] 597 del := &Delete{ 598 DML: &DML{ 599 RoutingParameters: &RoutingParameters{ 600 Opcode: MultiEqual, 601 Keyspace: ks.Keyspace, 602 Vindex: ks.Vindexes["hash"], 603 Values: []evalengine.Expr{evalengine.NewTupleExpr( 604 evalengine.NewLiteralInt(1), 605 evalengine.NewLiteralInt(5), 606 )}, 607 }, 608 Query: "dummy_delete", 609 }, 610 } 611 612 vc := newDMLTestVCursor("-20", "20-") 613 vc.shardForKsid = []string{"-20", "20-"} 614 _, err := del.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false) 615 require.NoError(t, err) 616 vc.ExpectLog(t, []string{ 617 `ResolveDestinations sharded [type:INT64 value:"1" type:INT64 value:"5"] Destinations:DestinationKeyspaceID(166b40b44aba4bd6),DestinationKeyspaceID(70bb023c810ca87a)`, 618 `ExecuteMultiShard sharded.-20: dummy_delete {} sharded.20-: dummy_delete {} true false`, 619 }) 620 }